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

taosdata / TDengine / #4727

08 Sep 2025 08:43AM UTC coverage: 59.125% (+0.01%) from 59.112%
#4727

push

travis-ci

web-flow
Merge pull request #32881 from taosdata/enh/add-new-windows-ci

fix(ci): update workflow reference to use new Windows CI YAML

135884 of 292179 branches covered (46.51%)

Branch coverage included in aggregate %.

204671 of 283811 relevant lines covered (72.12%)

29258962.23 hits per line

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

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

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

32
bool ignoreNegative(int8_t ignoreOption) { return (ignoreOption & 0x1) == 0x1; }
2,147,483,647✔
33
bool ignoreNull(int8_t ignoreOption) { return (ignoreOption & 0x2) == 0x2; }
4,151,190✔
34

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

209
void funcInputUpdate(SqlFunctionCtx* pCtx) {
59,784,681✔
210
  SFuncInputRowIter* pIter = &pCtx->rowIter;
59,784,681✔
211

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

408
int32_t funcInputGetNextRow(SqlFunctionCtx* pCtx, SFuncInputRow* pRow, bool* res) {
2,147,483,647✔
409
  SFuncInputRowIter* pIter = &pCtx->rowIter;
2,147,483,647✔
410
  if (pCtx->hasPrimaryKey) {
2,147,483,647✔
411
    if (pCtx->order == TSDB_ORDER_ASC) {
7,000!
412
      *res = funcInputGetNextRowAscPk(pIter, pRow);
7,000✔
413
      return TSDB_CODE_SUCCESS;
7,000✔
414
    } else {
415
      return funcInputGetNextRowDescPk(pIter, pRow, res);
×
416
    }
417
  } else {
418
    *res = funcInputGetNextRowNoPk(pIter, pRow);
2,147,483,647✔
419
    return TSDB_CODE_SUCCESS;
2,147,483,647✔
420
  }
421
  return TSDB_CODE_SUCCESS;
422
}
423

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

431
  for (int32_t j = 0; j < pCtx->subsidiaries.num; ++j) {
80,841,155✔
432
    SqlFunctionCtx* pc = pCtx->subsidiaries.pCtx[j];
40,425,206✔
433

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

438
    SColumnInfoData* pSrcCol = taosArrayGet(pSrcBlock->pDataBlock, srcSlotId);
40,425,206✔
439
    if (NULL == pSrcCol) {
40,417,385!
440
      return TSDB_CODE_OUT_OF_RANGE;
×
441
    }
442

443
    char* pData = colDataGetData(pSrcCol, rowIndex);
40,417,385!
444

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

448
    SColumnInfoData* pDstCol = taosArrayGet(pCtx->pDstBlock->pDataBlock, dstSlotId);
40,417,385✔
449
    if (NULL == pDstCol) {
40,414,150!
450
      return TSDB_CODE_OUT_OF_RANGE;
×
451
    }
452
    if (colDataIsNull_s(pSrcCol, rowIndex) == true) {
80,828,300✔
453
      colDataSetNULL(pDstCol, pos);
20!
454
    } else {
455
      int32_t code = colDataSetVal(pDstCol, pos, pData, false);
40,414,130✔
456
      if (TSDB_CODE_SUCCESS != code) {
40,417,351!
457
        return code;
×
458
      }
459
    }
460
  }
461
  return TSDB_CODE_SUCCESS;
40,415,949✔
462
}
463

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

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

469
int32_t functionSetup(SqlFunctionCtx* pCtx, SResultRowEntryInfo* pResultInfo) {
1,402,994,070✔
470
  if (pResultInfo->initialized) {
1,402,994,070✔
471
    return TSDB_CODE_SUCCESS;  // already initialized
255,602✔
472
  }
473

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

478
  initResultRowEntry(pResultInfo, pCtx->resDataInfo.interBufSize);
1,402,738,468✔
479
  return TSDB_CODE_SUCCESS;
1,402,738,468✔
480
}
481

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

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

495
  return code;
211,803,349✔
496
}
497

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

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

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

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

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

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

525
  return code;
194✔
526
}
527

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

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

541
static int64_t getNumOfElems(SqlFunctionCtx* pCtx) {
81,220,365✔
542
  int64_t numOfElem = 0;
81,220,365✔
543

544
  /*
545
   * 1. column data missing (schema modified) causes pInputCol->hasNull == true. pInput->colDataSMAIsSet == true;
546
   * 2. for general non-primary key columns, pInputCol->hasNull may be true or false, pInput->colDataSMAIsSet == true;
547
   * 3. for primary key column, pInputCol->hasNull always be false, pInput->colDataSMAIsSet == false;
548
   */
549
  SInputColumnInfoData* pInput = &pCtx->input;
81,220,365✔
550
  SColumnInfoData*      pInputCol = pInput->pData[0];
81,220,365✔
551
  if (1 == pInput->numOfRows && pInput->blankFill) {
81,220,365✔
552
    return 0;
534,900✔
553
  }
554
  if (pInput->colDataSMAIsSet && pInput->totalRows == pInput->numOfRows) {
80,685,465!
555
    numOfElem = pInput->numOfRows - pInput->pColumnDataAgg[0]->numOfNull;
3,615✔
556
  } else {
557
    if (pInputCol->hasNull) {
80,681,850✔
558
      for (int32_t i = pInput->startRowIndex; i < pInput->startRowIndex + pInput->numOfRows; ++i) {
607,189,779✔
559
        if (colDataIsNull(pInputCol, pInput->totalRows, i, NULL)) {
1,151,246,742!
560
          continue;
10,861,052✔
561
        }
562
        numOfElem += 1;
564,762,319✔
563
      }
564
    } else {
565
      // when counting on the primary time stamp column and no statistics data is presented, use the size value
566
      // directly.
567
      numOfElem = pInput->numOfRows;
49,115,442✔
568
    }
569
  }
570
  return numOfElem;
80,685,465✔
571
}
572

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

580
  SResultRowEntryInfo*  pResInfo = GET_RES_INFO(pCtx);
82,002,434✔
581
  SInputColumnInfoData* pInput = &pCtx->input;
82,002,434✔
582

583
  int32_t type = pInput->pData[0]->info.type;
82,002,434✔
584

585
  char*   buf = GET_ROWCELL_INTERBUF(pResInfo);
82,002,434✔
586
  int64_t val = *((int64_t*)buf);
82,002,434✔
587
  if (IS_NULL_TYPE(type)) {
82,002,434✔
588
    // select count(NULL) returns 0
589
    numOfElem = 1;
830,639✔
590
    val += 0;
830,639✔
591
  } else {
592
    numOfElem = getNumOfElems(pCtx);
81,171,795✔
593
    val += numOfElem;
81,217,016✔
594
  }
595
  taosSetInt64Aligned((int64_t*)buf, val);
596

597
  if (tsCountAlwaysReturnValue) {
82,047,655✔
598
    pResInfo->numOfRes = 1;
82,021,360✔
599
  } else {
600
    SET_VAL(pResInfo, val, 1);
26,295✔
601
  }
602

603
  return TSDB_CODE_SUCCESS;
82,047,655✔
604
}
605

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

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

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

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

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

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

631
int32_t sumFunction(SqlFunctionCtx* pCtx) {
51,087,499✔
632
  int32_t numOfElem = 0;
51,087,499✔
633

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

640
  void* pSumRes = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
51,087,499✔
641
  SUM_RES_SET_TYPE(pSumRes, pCtx->inputType, type);
51,087,499!
642

643
  if (IS_NULL_TYPE(type)) {
51,087,499✔
644
    numOfElem = 0;
319✔
645
    goto _sum_over;
319✔
646
  }
647

648
  if (pInput->colDataSMAIsSet) {
51,087,180✔
649
    numOfElem = pInput->numOfRows - pAgg->numOfNull;
3,904✔
650

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

669
    int32_t start = pInput->startRowIndex;
51,083,276✔
670
    int32_t numOfRows = pInput->numOfRows;
51,083,276✔
671

672
    if (IS_SIGNED_NUMERIC_TYPE(type) || type == TSDB_DATA_TYPE_BOOL) {
51,083,276!
673
      if (type == TSDB_DATA_TYPE_TINYINT || type == TSDB_DATA_TYPE_BOOL) {
43,355,918!
674
        LIST_ADD_N(SUM_RES_GET_ISUM(pSumRes), pCol, start, numOfRows, int8_t, numOfElem);
3,472,413!
675
      } else if (type == TSDB_DATA_TYPE_SMALLINT) {
42,444,235✔
676
        LIST_ADD_N(SUM_RES_GET_ISUM(pSumRes), pCol, start, numOfRows, int16_t, numOfElem);
459,280!
677
      } else if (type == TSDB_DATA_TYPE_INT) {
42,403,413✔
678
        LIST_ADD_N(SUM_RES_GET_ISUM(pSumRes), pCol, start, numOfRows, int32_t, numOfElem);
311,897,721✔
679
      } else if (type == TSDB_DATA_TYPE_BIGINT) {
12,475,511✔
680
        LIST_ADD_N(SUM_RES_GET_ISUM(pSumRes), pCol, start, numOfRows, int64_t, numOfElem);
34,639,895!
681
      }
682
    } else if (IS_UNSIGNED_NUMERIC_TYPE(type)) {
7,727,358!
683
      if (type == TSDB_DATA_TYPE_UTINYINT) {
737✔
684
        LIST_ADD_N(SUM_RES_GET_USUM(pSumRes), pCol, start, numOfRows, uint8_t, numOfElem);
140,043!
685
      } else if (type == TSDB_DATA_TYPE_USMALLINT) {
694✔
686
        LIST_ADD_N(SUM_RES_GET_USUM(pSumRes), pCol, start, numOfRows, uint16_t, numOfElem);
140,051!
687
      } else if (type == TSDB_DATA_TYPE_UINT) {
650✔
688
        LIST_ADD_N(SUM_RES_GET_USUM(pSumRes), pCol, start, numOfRows, uint32_t, numOfElem);
141,584!
689
      } else if (type == TSDB_DATA_TYPE_UBIGINT) {
184!
690
        LIST_ADD_N(SUM_RES_GET_USUM(pSumRes), pCol, start, numOfRows, uint64_t, numOfElem);
141,403!
691
      }
692
    } else if (type == TSDB_DATA_TYPE_DOUBLE) {
7,726,621✔
693
      LIST_ADD_N(SUM_RES_GET_DSUM(pSumRes), pCol, start, numOfRows, double, numOfElem);
7,344,426!
694
    } else if (type == TSDB_DATA_TYPE_FLOAT) {
5,934,682!
695
      LIST_ADD_N(SUM_RES_GET_DSUM(pSumRes), pCol, start, numOfRows, float, numOfElem);
22,380,954!
696
    } else if (IS_DECIMAL_TYPE(type)) {
×
697
      SUM_RES_SET_TYPE(pSumRes, pCtx->inputType, TSDB_DATA_TYPE_DECIMAL);
×
698
      int32_t overflow = false;
×
699
      if (TSDB_DATA_TYPE_DECIMAL64 == type) {
×
700
        LIST_ADD_DECIMAL_N(&SUM_RES_GET_DECIMAL_SUM(pSumRes), pCol, start, numOfRows, Decimal64, numOfElem);
×
701
      } else if (TSDB_DATA_TYPE_DECIMAL == type) {
×
702
        LIST_ADD_DECIMAL_N(&SUM_RES_GET_DECIMAL_SUM(pSumRes), pCol, start, numOfRows, Decimal128, numOfElem);
×
703
      }
704
      if (overflow) return TSDB_CODE_DECIMAL_OVERFLOW;
×
705
    }
706
  }
707

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

713
_sum_over:
51,331,482✔
714
  if (numOfElem == 0) {
51,087,499✔
715
    if (tsCountAlwaysReturnValue && pCtx->pExpr->pExpr->_function.pFunctNode->hasOriginalFunc &&
2,340,719!
716
        fmIsCountLikeFunc(pCtx->pExpr->pExpr->_function.pFunctNode->originalFuncId)) {
831,814✔
717
      numOfElem = 1;
×
718
    }
719
  }
720
  // data in the check operation are all null, not output
721
  SET_VAL(GET_RES_INFO(pCtx), numOfElem, 1);
51,087,499✔
722
  return TSDB_CODE_SUCCESS;
51,087,499✔
723
}
724

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

854
  SMinmaxResInfo* buf = GET_ROWCELL_INTERBUF(pResultInfo);
65,577,954✔
855
  buf->assign = false;
65,577,954✔
856
  buf->tuplePos.pageId = -1;
65,577,954✔
857

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

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

870
int32_t minFunction(SqlFunctionCtx* pCtx) {
38,400,972✔
871
  int32_t numOfElems = 0;
38,400,972✔
872
  int32_t code = doMinMaxHelper(pCtx, 1, &numOfElems);
38,400,972✔
873
  if (code != TSDB_CODE_SUCCESS) {
38,467,585!
874
    return code;
×
875
  }
876
  SET_VAL(GET_RES_INFO(pCtx), numOfElems, 1);
38,467,585✔
877
  return TSDB_CODE_SUCCESS;
38,467,585✔
878
}
879

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

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

894
int32_t minmaxFunctionFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
65,482,968✔
895
  int32_t code = TSDB_CODE_SUCCESS;
65,482,968✔
896

897
  SResultRowEntryInfo* pEntryInfo = GET_RES_INFO(pCtx);
65,482,968✔
898
  SMinmaxResInfo*      pRes = GET_ROWCELL_INTERBUF(pEntryInfo);
65,482,968✔
899

900
  int32_t slotId = pCtx->pExpr->base.resSchema.slotId;
65,482,968✔
901
  int32_t currentRow = pBlock->info.rows;
65,482,968✔
902

903
  SColumnInfoData* pCol = taosArrayGet(pBlock->pDataBlock, slotId);
65,482,968✔
904
  if (NULL == pCol) {
65,415,325!
905
    return TSDB_CODE_OUT_OF_RANGE;
×
906
  }
907
  pEntryInfo->isNullRes = (pEntryInfo->numOfRes == 0) ? 1 : 0;
65,415,325✔
908

909
  // NOTE: do nothing change it, for performance issue
910
  if (!pEntryInfo->isNullRes) {
65,415,325✔
911
    switch (pCol->info.type) {
63,868,666!
912
      case TSDB_DATA_TYPE_UBIGINT:
11,755,145✔
913
      case TSDB_DATA_TYPE_BIGINT:
914
        ((int64_t*)pCol->pData)[currentRow] = pRes->v;
11,755,145✔
915
        break;
11,755,145✔
916
      case TSDB_DATA_TYPE_UINT:
6,763,276✔
917
      case TSDB_DATA_TYPE_INT:
918
        colDataSetInt32(pCol, currentRow, (int32_t*)&pRes->v);
6,763,276✔
919
        break;
6,763,276✔
920
      case TSDB_DATA_TYPE_USMALLINT:
7,851,678✔
921
      case TSDB_DATA_TYPE_SMALLINT:
922
        colDataSetInt16(pCol, currentRow, (int16_t*)&pRes->v);
7,851,678✔
923
        break;
7,851,678✔
924
      case TSDB_DATA_TYPE_BOOL:
339,842✔
925
      case TSDB_DATA_TYPE_UTINYINT:
926
      case TSDB_DATA_TYPE_TINYINT:
927
        colDataSetInt8(pCol, currentRow, (int8_t*)&pRes->v);
339,842✔
928
        break;
339,842✔
929
      case TSDB_DATA_TYPE_DOUBLE:
14,302,689✔
930
        colDataSetDouble(pCol, currentRow, (double*)&pRes->v);
14,302,689✔
931
        break;
14,302,689✔
932
      case TSDB_DATA_TYPE_FLOAT: {
9,369,859✔
933
        float v = GET_FLOAT_VAL(&pRes->v);
9,369,859✔
934
        colDataSetFloat(pCol, currentRow, &v);
9,369,859✔
935
        break;
9,369,859✔
936
      }
937
      case TSDB_DATA_TYPE_VARBINARY:
13,533,030✔
938
      case TSDB_DATA_TYPE_VARCHAR:
939
      case TSDB_DATA_TYPE_NCHAR: {
940
        code = colDataSetVal(pCol, currentRow, pRes->str, false);
13,533,030✔
941
        if (TSDB_CODE_SUCCESS != code) {
13,499,286!
942
          return code;
×
943
        }
944
        break;
13,499,286✔
945
      }
946
      case TSDB_DATA_TYPE_DECIMAL64:
×
947
        code = colDataSetVal(pCol, currentRow, (const char*)&pRes->v, false);
×
948
        break;
×
949
      case TSDB_DATA_TYPE_DECIMAL:
×
950
        code = colDataSetVal(pCol, currentRow, (void*)pRes->dec, false);
×
951
        break;
×
952
    }
953
  } else {
954
    colDataSetNULL(pCol, currentRow);
1,546,659!
955
  }
956

957
  if (IS_VAR_DATA_TYPE(pCol->info.type)) taosMemoryFreeClear(pRes->str);
65,381,581!
958
  if (pCtx->subsidiaries.num > 0) {
65,465,611✔
959
    if (pEntryInfo->numOfRes > 0) {
47,491,641✔
960
      code = setSelectivityValue(pCtx, pBlock, &pRes->tuplePos, currentRow);
47,490,413✔
961
    } else {
962
      code = setNullSelectivityValue(pCtx, pBlock, currentRow);
1,228✔
963
    }
964
  }
965

966
  return code;
65,444,791✔
967
}
968

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

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

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

985
  return TSDB_CODE_SUCCESS;
1,371✔
986
}
987

988
int32_t setSelectivityValue(SqlFunctionCtx* pCtx, SSDataBlock* pBlock, const STuplePos* pTuplePos, int32_t rowIndex) {
653,987,225✔
989
  if (pCtx->subsidiaries.num <= 0) {
653,987,225✔
990
    return TSDB_CODE_SUCCESS;
248,873,805✔
991
  }
992

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

1004
    bool* nullList = (bool*)p;
413,133,913✔
1005
    char* pStart = (char*)(nullList + numOfCols * sizeof(bool));
413,133,913✔
1006

1007
    // todo set the offset value to optimize the performance.
1008
    for (int32_t j = 0; j < numOfCols; ++j) {
822,845,550✔
1009
      SqlFunctionCtx* pc = pCtx->subsidiaries.pCtx[j];
413,154,307✔
1010
      int32_t         dstSlotId = pc->pExpr->base.resSchema.slotId;
413,154,307✔
1011

1012
      SColumnInfoData* pDstCol = taosArrayGet(pBlock->pDataBlock, dstSlotId);
413,154,307✔
1013
      if (NULL == pDstCol) {
410,844,619!
1014
        return terrno;
×
1015
      }
1016
      if (nullList[j]) {
410,858,184✔
1017
        colDataSetNULL(pDstCol, rowIndex);
29,729✔
1018
      } else {
1019
        code = colDataSetValOrCover(pDstCol, rowIndex, pStart, false);
410,828,455✔
1020
        if (TSDB_CODE_SUCCESS != code) {
409,681,908!
1021
          return code;
×
1022
        }
1023
      }
1024
      pStart += pDstCol->info.bytes;
409,711,637✔
1025
    }
1026
  }
1027

1028
  return TSDB_CODE_SUCCESS;
409,674,729✔
1029
}
1030

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

1038
  int32_t code = TSDB_CODE_SUCCESS;
166,358,456✔
1039
  for (int32_t j = 0; j < pCtx->subsidiaries.num; ++j) {
332,573,977✔
1040
    SqlFunctionCtx* pc = pCtx->subsidiaries.pCtx[j];
166,359,444✔
1041

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

1046
    SColumnInfoData* pSrcCol = taosArrayGet(pCtx->pSrcBlock->pDataBlock, srcSlotId);
166,359,444✔
1047
    if (NULL == pSrcCol) {
166,193,310!
1048
      return TSDB_CODE_OUT_OF_RANGE;
×
1049
    }
1050

1051
    char* pData = colDataGetData(pSrcCol, rowIndex);
166,193,310!
1052

1053
    // append to dest col
1054
    int32_t dstSlotId = pc->pExpr->base.resSchema.slotId;
166,193,310✔
1055

1056
    SColumnInfoData* pDstCol = taosArrayGet(pCtx->pDstBlock->pDataBlock, dstSlotId);
166,193,310✔
1057
    if (NULL == pDstCol) {
166,085,912!
1058
      return TSDB_CODE_OUT_OF_RANGE;
×
1059
    }
1060

1061
    if (colDataIsNull_s(pSrcCol, rowIndex) == true) {
332,171,824✔
1062
      colDataSetNULL(pDstCol, pos);
400✔
1063
    } else {
1064
      code = colDataSetVal(pDstCol, pos, pData, false);
166,085,512✔
1065
      if (TSDB_CODE_SUCCESS != code) {
166,215,121!
1066
        return code;
×
1067
      }
1068
    }
1069
  }
1070
  return code;
166,214,533✔
1071
}
1072

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

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

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

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

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

1165
int32_t getStdInfoSize() { return (int32_t)sizeof(SStdRes); }
2,897,276✔
1166

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

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

1180
  SStdRes* pRes = GET_ROWCELL_INTERBUF(pResultInfo);
22,232,334✔
1181
  (void)memset(pRes, 0, sizeof(SStdRes));
22,232,334✔
1182
  return TSDB_CODE_SUCCESS;
22,232,334✔
1183
}
1184

1185
int32_t stdFunction(SqlFunctionCtx* pCtx) {
22,209,136✔
1186
  int32_t numOfElem = 0;
22,209,136✔
1187

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

1192
  SStdRes* pStdRes = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
22,209,136✔
1193
  pStdRes->type = type;
22,209,136✔
1194

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

1198
  int32_t start = pInput->startRowIndex;
22,209,136✔
1199
  int32_t numOfRows = pInput->numOfRows;
22,209,136✔
1200

1201
  if (IS_NULL_TYPE(type)) {
22,209,136✔
1202
    numOfElem = 0;
217✔
1203
    goto _stddev_over;
217✔
1204
  }
1205

1206
  switch (type) {
22,208,919!
1207
    case TSDB_DATA_TYPE_TINYINT: {
4,700,705✔
1208
      int8_t* plist = (int8_t*)pCol->pData;
4,700,705✔
1209
      for (int32_t i = start; i < numOfRows + start; ++i) {
19,040,890✔
1210
        if (pCol->hasNull && colDataIsNull_f(pCol, i)) {
14,340,185!
1211
          continue;
158,689✔
1212
        }
1213

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

1220
      break;
4,700,705✔
1221
    }
1222

1223
    case TSDB_DATA_TYPE_SMALLINT: {
157,515✔
1224
      int16_t* plist = (int16_t*)pCol->pData;
157,515✔
1225
      for (int32_t i = start; i < numOfRows + pInput->startRowIndex; ++i) {
2,281,964✔
1226
        if (pCol->hasNull && colDataIsNull_f(pCol, i)) {
2,124,449!
1227
          continue;
17,613✔
1228
        }
1229

1230
        numOfElem += 1;
2,106,836✔
1231
        pStdRes->count += 1;
2,106,836✔
1232
        pStdRes->isum += plist[i];
2,106,836✔
1233
        pStdRes->quadraticISum += plist[i] * plist[i];
2,106,836✔
1234
      }
1235
      break;
157,515✔
1236
    }
1237

1238
    case TSDB_DATA_TYPE_INT: {
6,678,820✔
1239
      int32_t* plist = (int32_t*)pCol->pData;
6,678,820✔
1240
      for (int32_t i = start; i < numOfRows + pInput->startRowIndex; ++i) {
24,714,001✔
1241
        if (pCol->hasNull && colDataIsNull_f(pCol, i)) {
18,035,181!
1242
          continue;
23,551✔
1243
        }
1244

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

1251
      break;
6,678,820✔
1252
    }
1253

1254
    case TSDB_DATA_TYPE_BIGINT: {
4,928,410✔
1255
      int64_t* plist = (int64_t*)pCol->pData;
4,928,410✔
1256
      for (int32_t i = start; i < numOfRows + pInput->startRowIndex; ++i) {
19,643,228✔
1257
        if (pCol->hasNull && colDataIsNull_f(pCol, i)) {
14,714,818!
1258
          continue;
18,985✔
1259
        }
1260

1261
        numOfElem += 1;
14,695,833✔
1262
        pStdRes->count += 1;
14,695,833✔
1263
        pStdRes->isum += plist[i];
14,695,833✔
1264
        pStdRes->quadraticISum += plist[i] * plist[i];
14,695,833✔
1265
      }
1266
      break;
4,928,410✔
1267
    }
1268

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

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

1282
      break;
25✔
1283
    }
1284

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

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

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

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

1313
      break;
25✔
1314
    }
1315

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

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

1331
    case TSDB_DATA_TYPE_FLOAT: {
5,701,028✔
1332
      float* plist = (float*)pCol->pData;
5,701,028✔
1333
      for (int32_t i = start; i < numOfRows + pInput->startRowIndex; ++i) {
27,046,548✔
1334
        if (pCol->hasNull && colDataIsNull_f(pCol, i)) {
21,345,520✔
1335
          continue;
84,402✔
1336
        }
1337

1338
        numOfElem += 1;
21,261,118✔
1339
        pStdRes->count += 1;
21,261,118✔
1340
        pStdRes->dsum += plist[i];
21,261,118✔
1341
        pStdRes->quadraticDSum += plist[i] * plist[i];
21,261,118✔
1342
      }
1343
      break;
5,701,028✔
1344
    }
1345

1346
    case TSDB_DATA_TYPE_DOUBLE: {
45,312✔
1347
      double* plist = (double*)pCol->pData;
45,312✔
1348
      for (int32_t i = start; i < numOfRows + pInput->startRowIndex; ++i) {
2,413,625✔
1349
        if (pCol->hasNull && colDataIsNull_f(pCol, i)) {
2,368,313!
1350
          continue;
437,236✔
1351
        }
1352

1353
        numOfElem += 1;
1,931,077✔
1354
        pStdRes->count += 1;
1,931,077✔
1355
        pStdRes->dsum += plist[i];
1,931,077✔
1356
        pStdRes->quadraticDSum += plist[i] * plist[i];
1,931,077✔
1357
      }
1358
      break;
45,312✔
1359
    }
1360

1361
    default:
×
1362
      break;
×
1363
  }
1364

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

1371
static void stdTransferInfo(SStdRes* pInput, SStdRes* pOutput) {
2,894,985✔
1372
  if (IS_NULL_TYPE(pInput->type)) {
2,894,985✔
1373
    return;
64✔
1374
  }
1375
  pOutput->type = pInput->type;
2,894,921✔
1376
  if (IS_SIGNED_NUMERIC_TYPE(pOutput->type)) {
2,894,921!
1377
    pOutput->quadraticISum += pInput->quadraticISum;
1,741,549✔
1378
    pOutput->isum += pInput->isum;
1,741,549✔
1379
  } else if (IS_UNSIGNED_NUMERIC_TYPE(pOutput->type)) {
1,153,372!
1380
    pOutput->quadraticUSum += pInput->quadraticUSum;
1✔
1381
    pOutput->usum += pInput->usum;
1✔
1382
  } else {
1383
    pOutput->quadraticDSum += pInput->quadraticDSum;
1,153,371✔
1384
    pOutput->dsum += pInput->dsum;
1,153,371✔
1385
  }
1386

1387
  pOutput->count += pInput->count;
2,894,921✔
1388
}
1389

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

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

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

1403
  SStdRes* pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
2,894,985✔
1404

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

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

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

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

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

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

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

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

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

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

1489
  if (pStddevRes->count == 0) {
19,264,931✔
1490
    GET_RES_INFO(pCtx)->numOfRes = 0;
25,121✔
1491
    return functionFinalize(pCtx, pBlock);
25,121✔
1492
  }
1493

1494
  if (IS_SIGNED_NUMERIC_TYPE(type)) {
19,239,810!
1495
    avg = pStddevRes->isum / ((double)pStddevRes->count);
14,661,870✔
1496
    pStddevRes->result = sqrt(fabs(pStddevRes->quadraticISum / ((double)pStddevRes->count) - avg * avg));
14,661,870✔
1497
  } else if (IS_UNSIGNED_NUMERIC_TYPE(type)) {
4,577,940!
1498
    avg = pStddevRes->usum / ((double)pStddevRes->count);
10✔
1499
    pStddevRes->result = sqrt(fabs(pStddevRes->quadraticUSum / ((double)pStddevRes->count) - avg * avg));
10✔
1500
  } else {
1501
    avg = pStddevRes->dsum / ((double)pStddevRes->count);
4,577,930✔
1502
    pStddevRes->result = sqrt(fabs(pStddevRes->quadraticDSum / ((double)pStddevRes->count) - avg * avg));
4,577,930✔
1503
  }
1504

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

1510
  return functionFinalize(pCtx, pBlock);
19,239,810✔
1511
}
1512

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

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

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

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

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

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

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

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

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

1564
  taosMemoryFree(res);
2,897,203!
1565
  return code;
2,897,204✔
1566
}
1567

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

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

1576
  stdTransferInfo(pSBuf, pDBuf);
×
1577

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

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

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

1596
  SLeastSQRInfo* pInfo = GET_ROWCELL_INTERBUF(pResultInfo);
15,627,008✔
1597

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

1605
int32_t leastSQRFunction(SqlFunctionCtx* pCtx) {
18,027,269✔
1606
  int32_t numOfElem = 0;
18,027,269✔
1607

1608
  SInputColumnInfoData* pInput = &pCtx->input;
18,027,269✔
1609
  int32_t               type = pInput->pData[0]->info.type;
18,027,269✔
1610

1611
  SLeastSQRInfo* pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
18,027,269✔
1612

1613
  SColumnInfoData* pCol = pInput->pData[0];
18,027,269✔
1614

1615
  double(*param)[3] = pInfo->matrix;
18,027,269✔
1616
  double x = pInfo->startVal;
18,027,269✔
1617

1618
  int32_t start = pInput->startRowIndex;
18,027,269✔
1619
  int32_t numOfRows = pInput->numOfRows;
18,027,269✔
1620

1621
  switch (type) {
18,027,269!
1622
    case TSDB_DATA_TYPE_TINYINT: {
2,033,034✔
1623
      int8_t* plist = (int8_t*)pCol->pData;
2,033,034✔
1624
      for (int32_t i = start; i < numOfRows + pInput->startRowIndex; ++i) {
7,466,586✔
1625
        if (pCol->hasNull && colDataIsNull_f(pCol, i)) {
5,433,552!
1626
          continue;
285,160✔
1627
        }
1628
        numOfElem++;
5,148,392✔
1629
        LEASTSQR_CAL(param, x, plist, i, pInfo->stepVal);
5,148,392✔
1630
      }
1631
      break;
2,033,034✔
1632
    }
1633
    case TSDB_DATA_TYPE_SMALLINT: {
2,168,695✔
1634
      int16_t* plist = (int16_t*)pCol->pData;
2,168,695✔
1635
      for (int32_t i = start; i < numOfRows + pInput->startRowIndex; ++i) {
6,963,479✔
1636
        if (pCol->hasNull && colDataIsNull_f(pCol, i)) {
4,794,784!
1637
          continue;
1,248✔
1638
        }
1639

1640
        numOfElem++;
4,793,536✔
1641
        LEASTSQR_CAL(param, x, plist, i, pInfo->stepVal);
4,793,536✔
1642
      }
1643
      break;
2,168,695✔
1644
    }
1645

1646
    case TSDB_DATA_TYPE_INT: {
4,797,119✔
1647
      int32_t* plist = (int32_t*)pCol->pData;
4,797,119✔
1648
      for (int32_t i = start; i < numOfRows + pInput->startRowIndex; ++i) {
18,100,583✔
1649
        if (pCol->hasNull && colDataIsNull_f(pCol, i)) {
13,303,464!
1650
          continue;
1,533✔
1651
        }
1652

1653
        numOfElem++;
13,301,931✔
1654
        LEASTSQR_CAL(param, x, plist, i, pInfo->stepVal);
13,301,931✔
1655
      }
1656
      break;
4,797,119✔
1657
    }
1658

1659
    case TSDB_DATA_TYPE_BIGINT: {
5,476,684✔
1660
      int64_t* plist = (int64_t*)pCol->pData;
5,476,684✔
1661
      for (int32_t i = start; i < numOfRows + pInput->startRowIndex; ++i) {
18,260,910✔
1662
        if (pCol->hasNull && colDataIsNull_f(pCol, i)) {
12,784,226!
1663
          continue;
948✔
1664
        }
1665

1666
        numOfElem++;
12,783,278✔
1667
        LEASTSQR_CAL(param, x, plist, i, pInfo->stepVal);
12,783,278✔
1668
      }
1669
      break;
5,476,684✔
1670
    }
1671

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

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

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

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

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

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

1722
    case TSDB_DATA_TYPE_FLOAT: {
3,536,231✔
1723
      float* plist = (float*)pCol->pData;
3,536,231✔
1724
      for (int32_t i = start; i < numOfRows + pInput->startRowIndex; ++i) {
11,973,470✔
1725
        if (pCol->hasNull && colDataIsNull_f(pCol, i)) {
8,437,239!
1726
          continue;
137,948✔
1727
        }
1728

1729
        numOfElem++;
8,299,291✔
1730
        LEASTSQR_CAL(param, x, plist, i, pInfo->stepVal);
8,299,291✔
1731
      }
1732
      break;
3,536,231✔
1733
    }
1734

1735
    case TSDB_DATA_TYPE_DOUBLE: {
14,997✔
1736
      double* plist = (double*)pCol->pData;
14,997✔
1737
      for (int32_t i = start; i < numOfRows + pInput->startRowIndex; ++i) {
1,282,043✔
1738
        if (pCol->hasNull && colDataIsNull_f(pCol, i)) {
1,267,046!
1739
          continue;
1,248✔
1740
        }
1741

1742
        numOfElem++;
1,265,798✔
1743
        LEASTSQR_CAL(param, x, plist, i, pInfo->stepVal);
1,265,798✔
1744
      }
1745
      break;
14,997✔
1746
    }
1747
    case TSDB_DATA_TYPE_NULL: {
×
1748
      GET_RES_INFO(pCtx)->isNullRes = 1;
×
1749
      numOfElem = 1;
×
1750
      break;
×
1751
    }
1752

1753
    default:
×
1754
      break;
×
1755
  }
1756

1757
  pInfo->startVal = x;
18,027,269✔
1758
  pInfo->num += numOfElem;
18,027,269✔
1759

1760
  SET_VAL(GET_RES_INFO(pCtx), numOfElem, 1);
18,027,269✔
1761

1762
  return TSDB_CODE_SUCCESS;
18,027,269✔
1763
}
1764

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

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

1776
  if (0 == pInfo->num) {
15,595,839✔
1777
    colDataSetNULL(pCol, currentRow);
11,775!
1778
    return TSDB_CODE_SUCCESS;
11,775✔
1779
  }
1780

1781
  double(*param)[3] = pInfo->matrix;
15,584,064✔
1782

1783
  param[1][1] = (double)pInfo->num;
15,584,064✔
1784
  param[1][0] = param[0][1];
15,584,064✔
1785

1786
  double param00 = param[0][0] - param[1][0] * (param[0][1] / param[1][1]);
15,584,064✔
1787
  double param02 = param[0][2] - param[1][2] * (param[0][1] / param[1][1]);
15,584,064✔
1788

1789
  if (0 == param00) {
15,584,064✔
1790
    colDataSetNULL(pCol, currentRow);
11,553,211!
1791
    return TSDB_CODE_SUCCESS;
11,553,211✔
1792
  }
1793

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

1799
  param12 /= param[1][1];
4,030,853✔
1800

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

1816
  int32_t code = colDataSetVal(pCol, currentRow, buf, pResInfo->isNullRes);
4,030,860✔
1817

1818
  return code;
4,030,860✔
1819
}
1820

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

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

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

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

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

1862
  return TSDB_CODE_SUCCESS;
3,430✔
1863
}
1864

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

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

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

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

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

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

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

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

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

1927
      pInfo->numOfElems += (pInput->numOfRows - pAgg->numOfNull);
3,567,837✔
1928
    } else {
1929
      // check the valid data one by one
1930
      int32_t start = pInput->startRowIndex;
8,656✔
1931
      for (int32_t i = start; i < pInput->numOfRows + start; ++i) {
17,744,743✔
1932
        if (colDataIsNull_f(pCol, i)) {
17,736,087!
1933
          continue;
1,632✔
1934
        }
1935

1936
        char* data = colDataGetData(pCol, i);
17,734,455!
1937

1938
        double v = 0;
17,734,455✔
1939
        GET_TYPED_DATA(v, double, type, data, typeGetTypeModFromColInfo(&pCol->info));
17,734,455!
1940
        if (v < GET_DOUBLE_VAL(&pInfo->minval)) {
17,734,455✔
1941
          SET_DOUBLE_VAL(&pInfo->minval, v);
2,447✔
1942
        }
1943

1944
        if (v > GET_DOUBLE_VAL(&pInfo->maxval)) {
17,734,455✔
1945
          SET_DOUBLE_VAL(&pInfo->maxval, v);
409,514✔
1946
        }
1947

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

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

1968
    SET_VAL(pResInfo, numOfElems, 1);
3,575,189!
1969
  }
1970

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

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

1979
  int32_t code = 0;
3,426✔
1980
  double  v = 0;
3,426✔
1981

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

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

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

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

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

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

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

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

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

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

2033
      tMemBucketDestroy(pMemBucket);
2,121✔
2034
      return functionFinalize(pCtx, pBlock);
2,121✔
2035
    }
2036
  } else {
2037
    return functionFinalize(pCtx, pBlock);
1,263✔
2038
  }
2039

2040
_fin_error:
×
2041

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

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

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

2061
static int8_t getApercentileAlgo(char* algoStr) {
14,548,769✔
2062
  int8_t algoType;
2063
  if (strcasecmp(algoStr, "default") == 0) {
14,548,769✔
2064
    algoType = APERCT_ALGO_DEFAULT;
11,424✔
2065
  } else if (strcasecmp(algoStr, "t-digest") == 0) {
14,537,345!
2066
    algoType = APERCT_ALGO_TDIGEST;
14,537,350✔
2067
  } else {
2068
    algoType = APERCT_ALGO_UNKNOWN;
×
2069
  }
2070

2071
  return algoType;
14,548,769✔
2072
}
2073

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

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

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

2091
  SAPercentileInfo* pInfo = GET_ROWCELL_INTERBUF(pResultInfo);
14,663,668✔
2092

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

2097
  if (pCtx->numOfParams == 2) {
14,663,666✔
2098
    pInfo->algo = APERCT_ALGO_DEFAULT;
114,895✔
2099
  } else if (pCtx->numOfParams == 3) {
14,548,771!
2100
    pInfo->algo = getApercentileAlgo(varDataVal(pCtx->param[2].param.pz));
14,548,771✔
2101
    if (pInfo->algo == APERCT_ALGO_UNKNOWN) {
14,548,771!
2102
      return TSDB_CODE_FUNC_FUNTION_PARA_VALUE;
×
2103
    }
2104
  }
2105

2106
  char* tmp = (char*)pInfo + sizeof(SAPercentileInfo);
14,663,666✔
2107
  if (pInfo->algo == APERCT_ALGO_TDIGEST) {
14,663,666✔
2108
    pInfo->pTDigest = tdigestNewFrom(tmp, COMPRESSION);
14,537,350✔
2109
  } else {
2110
    buildHistogramInfo(pInfo);
126,316✔
2111
    pInfo->pHisto = tHistogramCreateFrom(tmp, MAX_HISTOGRAM_BIN);
126,314✔
2112
    qDebug("%s set up histogram, numOfElems:%" PRId64 ", numOfEntry:%d, pHisto:%p, elems:%p", __FUNCTION__,
126,315✔
2113
           pInfo->pHisto->numOfElems, pInfo->pHisto->numOfEntries, pInfo->pHisto, pInfo->pHisto->elems);
2114
  }
2115

2116
  return TSDB_CODE_SUCCESS;
14,663,669✔
2117
}
2118

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

2124
  SColumnInfoData* pCol = pInput->pData[0];
11,689,317✔
2125
  int32_t          type = pCol->info.type;
11,689,317✔
2126

2127
  SAPercentileInfo* pInfo = GET_ROWCELL_INTERBUF(pResInfo);
11,689,317✔
2128

2129
  int32_t start = pInput->startRowIndex;
11,689,317✔
2130
  if (pInfo->algo == APERCT_ALGO_TDIGEST) {
11,689,317✔
2131
    buildTDigestInfo(pInfo);
11,542,521✔
2132
    tdigestAutoFill(pInfo->pTDigest, COMPRESSION);
11,542,521✔
2133
    for (int32_t i = start; i < pInput->numOfRows + start; ++i) {
46,894,703✔
2134
      if (colDataIsNull_f(pCol, i)) {
35,352,185✔
2135
        continue;
210,541✔
2136
      }
2137
      numOfElems += 1;
35,141,644✔
2138
      char* data = colDataGetData(pCol, i);
35,141,644!
2139

2140
      double  v = 0;  // value
35,141,644✔
2141
      int64_t w = 1;  // weigth
35,141,644✔
2142
      GET_TYPED_DATA(v, double, type, data, typeGetTypeModFromColInfo(&pCol->info));
35,141,644!
2143
      int32_t code = tdigestAdd(pInfo->pTDigest, v, w);
35,141,644✔
2144
      if (code != TSDB_CODE_SUCCESS) {
35,141,641!
2145
        return code;
×
2146
      }
2147
    }
2148
  } else {
2149
    // might be a race condition here that pHisto can be overwritten or setup function
2150
    // has not been called, need to relink the buffer pHisto points to.
2151
    buildHistogramInfo(pInfo);
146,796✔
2152
    qDebug("%s before add %d elements into histogram, total:%" PRId64 ", numOfEntry:%d, pHisto:%p, elems: %p",
146,796✔
2153
           __FUNCTION__, numOfElems, pInfo->pHisto->numOfElems, pInfo->pHisto->numOfEntries, pInfo->pHisto,
2154
           pInfo->pHisto->elems);
2155
    for (int32_t i = start; i < pInput->numOfRows + start; ++i) {
5,381,891✔
2156
      if (colDataIsNull_f(pCol, i)) {
5,235,128✔
2157
        continue;
568,910✔
2158
      }
2159
      numOfElems += 1;
4,666,218✔
2160
      char* data = colDataGetData(pCol, i);
4,666,218!
2161

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

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

2175
  SET_VAL(pResInfo, numOfElems, 1);
11,689,319✔
2176
  return TSDB_CODE_SUCCESS;
11,689,319✔
2177
}
2178

2179
static int32_t apercentileTransferInfo(SAPercentileInfo* pInput, SAPercentileInfo* pOutput, bool* hasRes) {
3,015,109✔
2180
  pOutput->percent = pInput->percent;
3,015,109✔
2181
  pOutput->algo = pInput->algo;
3,015,109✔
2182
  if (pOutput->algo == APERCT_ALGO_TDIGEST) {
3,015,109✔
2183
    buildTDigestInfo(pInput);
3,012,854✔
2184
    tdigestAutoFill(pInput->pTDigest, COMPRESSION);
3,012,854✔
2185

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

2190
    if (hasRes) {
3,012,853!
2191
      *hasRes = true;
3,012,853✔
2192
    }
2193

2194
    buildTDigestInfo(pOutput);
3,012,853✔
2195
    TDigest* pTDigest = pOutput->pTDigest;
3,012,853✔
2196
    tdigestAutoFill(pTDigest, COMPRESSION);
3,012,853✔
2197

2198
    if (pTDigest->num_centroids <= 0 && pTDigest->num_buffered_pts == 0) {
3,012,853!
2199
      (void)memcpy(pTDigest, pInput->pTDigest, (size_t)TDIGEST_SIZE(COMPRESSION));
3,012,853✔
2200
      tdigestAutoFill(pTDigest, COMPRESSION);
3,012,853✔
2201
    } else {
2202
      int32_t code = tdigestMerge(pTDigest, pInput->pTDigest);
×
2203
      if (TSDB_CODE_SUCCESS != code) {
×
2204
        return code;
×
2205
      }
2206
    }
2207
  } else {
2208
    buildHistogramInfo(pInput);
2,255✔
2209
    if (pInput->pHisto->numOfElems <= 0) {
2,255✔
2210
      return TSDB_CODE_SUCCESS;
59✔
2211
    }
2212

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

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

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

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

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

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

2248
int32_t apercentileFunctionMerge(SqlFunctionCtx* pCtx) {
3,015,104✔
2249
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
3,015,104✔
2250

2251
  SInputColumnInfoData* pInput = &pCtx->input;
3,015,104✔
2252

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

2258
  SAPercentileInfo* pInfo = GET_ROWCELL_INTERBUF(pResInfo);
3,015,104✔
2259

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

2262
  bool    hasRes = false;
3,015,104✔
2263
  int32_t start = pInput->startRowIndex;
3,015,104✔
2264
  for (int32_t i = start; i < start + pInput->numOfRows; ++i) {
6,030,213✔
2265
    char* data = colDataGetData(pCol, i);
3,015,109!
2266

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

2274
  if (pInfo->algo != APERCT_ALGO_TDIGEST) {
3,015,104✔
2275
    buildHistogramInfo(pInfo);
2,250✔
2276
    qDebug("%s after merge, total:%" PRId64 ", numOfEntry:%d, %p", __FUNCTION__, pInfo->pHisto->numOfElems,
2,250✔
2277
           pInfo->pHisto->numOfEntries, pInfo->pHisto);
2278
  }
2279

2280
  SET_VAL(pResInfo, hasRes ? 1 : 0, 1);
3,015,104✔
2281
  return TSDB_CODE_SUCCESS;
3,015,104✔
2282
}
2283

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

2288
  if (pInfo->algo == APERCT_ALGO_TDIGEST) {
11,631,038✔
2289
    buildTDigestInfo(pInfo);
11,524,457✔
2290
    tdigestAutoFill(pInfo->pTDigest, COMPRESSION);
11,524,457✔
2291
    if (pInfo->pTDigest->size > 0) {
11,524,456!
2292
      pInfo->result = tdigestQuantile(pInfo->pTDigest, pInfo->percent / 100);
11,524,456✔
2293
    } else {  // no need to free
2294
      // setNull(pCtx->pOutput, pCtx->outputType, pCtx->outputBytes);
2295
      return TSDB_CODE_SUCCESS;
×
2296
    }
2297
  } else {
2298
    buildHistogramInfo(pInfo);
106,581✔
2299
    if (pInfo->pHisto->numOfElems > 0) {
106,581✔
2300
      qDebug("%s get the final res, elements:%" PRId64 ", numOfEntry:%d, pHisto:%p, elems:%p", __FUNCTION__,
83,775✔
2301
             pInfo->pHisto->numOfElems, pInfo->pHisto->numOfEntries, pInfo->pHisto, pInfo->pHisto->elems);
2302

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

2321
  return functionFinalize(pCtx, pBlock);
11,631,048✔
2322
}
2323

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

2328
  int32_t resultBytes = getApercentileMaxSize();
3,015,204✔
2329
  char*   res = taosMemoryCalloc(resultBytes + VARSTR_HEADER_SIZE, sizeof(char));
3,015,204!
2330
  if (NULL == res) {
3,015,204!
2331
    return terrno;
×
2332
  }
2333

2334
  if (pInfo->algo == APERCT_ALGO_TDIGEST) {
3,015,204✔
2335
    (void)memcpy(varDataVal(res), pInfo, resultBytes);
3,012,884✔
2336
    varDataSetLen(res, resultBytes);
3,012,884✔
2337
  } else {
2338
    (void)memcpy(varDataVal(res), pInfo, resultBytes);
2,320✔
2339
    varDataSetLen(res, resultBytes);
2,320✔
2340
  }
2341

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

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

2351
  taosMemoryFree(res);
3,015,204!
2352
  return code;
3,015,204✔
2353
}
2354

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

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

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

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

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

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

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

2405
  SFirstLastRes* pResult = GET_ROWCELL_INTERBUF(pEntry);
19,172✔
2406
  if (pResult->hasResult) {
19,172✔
2407
    if (pResult->pkBytes > 0) {
19,141✔
2408
      pResult->pkData = pResult->buf + pResult->bytes;
1,294✔
2409
    } else {
2410
      pResult->pkData = NULL;
17,847✔
2411
    }
2412
    if (pResult->ts < pBlockInfo->window.skey) {
19,141✔
2413
      return FUNC_DATA_REQUIRED_NOT_LOAD;
13,686✔
2414
    } else if (pResult->ts == pBlockInfo->window.skey) {
5,455✔
2415
      if (NULL == pResult->pkData) {
626✔
2416
        return FUNC_DATA_REQUIRED_NOT_LOAD;
313✔
2417
      }
2418
      if (comparePkDataWithSValue(pResult->pkType, pResult->pkData, pBlockInfo->pks + 0, TSDB_ORDER_ASC) < 0) {
313✔
2419
        return FUNC_DATA_REQUIRED_NOT_LOAD;
26✔
2420
      }
2421
    }
2422
    return FUNC_DATA_REQUIRED_DATA_LOAD;
5,116✔
2423
  } else {
2424
    return FUNC_DATA_REQUIRED_DATA_LOAD;
31✔
2425
  }
2426
}
2427

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

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

2436
  SFirstLastRes* pResult = GET_ROWCELL_INTERBUF(pEntry);
24,300✔
2437
  if (pResult->hasResult) {
24,300✔
2438
    if (pResult->pkBytes > 0) {
24,260✔
2439
      pResult->pkData = pResult->buf + pResult->bytes;
1,049✔
2440
    } else {
2441
      pResult->pkData = NULL;
23,211✔
2442
    }
2443
    if (pResult->ts > pBlockInfo->window.ekey) {
24,260✔
2444
      return FUNC_DATA_REQUIRED_NOT_LOAD;
15,554✔
2445
    } else if (pResult->ts == pBlockInfo->window.ekey && pResult->pkData) {
8,706✔
2446
      if (comparePkDataWithSValue(pResult->pkType, pResult->pkData, pBlockInfo->pks + 1, TSDB_ORDER_DESC) < 0) {
689✔
2447
        return FUNC_DATA_REQUIRED_NOT_LOAD;
234✔
2448
      }
2449
    }
2450
    return FUNC_DATA_REQUIRED_DATA_LOAD;
8,472✔
2451
  } else {
2452
    return FUNC_DATA_REQUIRED_DATA_LOAD;
40✔
2453
  }
2454
}
2455

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

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

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

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

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

2484
  return *(TSKEY*)colDataGetData(pTsColInfo, rowIndex);
881,927,585!
2485
}
2486

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

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

2501
static int32_t prepareBuf(SqlFunctionCtx* pCtx) {
590,779,539✔
2502
  if (pCtx->subsidiaries.rowLen == 0) {
590,779,539✔
2503
    int32_t rowLen = 0;
1,909,681✔
2504
    for (int32_t j = 0; j < pCtx->subsidiaries.num; ++j) {
3,824,502✔
2505
      SqlFunctionCtx* pc = pCtx->subsidiaries.pCtx[j];
1,914,821✔
2506
      rowLen += pc->pExpr->base.resSchema.bytes;
1,914,821✔
2507
    }
2508

2509
    pCtx->subsidiaries.rowLen = rowLen + pCtx->subsidiaries.num * sizeof(bool);
1,909,681✔
2510
    pCtx->subsidiaries.buf = taosMemoryMalloc(pCtx->subsidiaries.rowLen);
1,909,681!
2511
    if (NULL == pCtx->subsidiaries.buf) {
1,891,825!
2512
      return terrno;
×
2513
    }
2514
  }
2515
  return TSDB_CODE_SUCCESS;
590,761,683✔
2516
}
2517

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

2522
  if (pCtx->subsidiaries.num <= 0) {
518,965,054✔
2523
    return TSDB_CODE_SUCCESS;
180,746,130✔
2524
  }
2525

2526
  if (!pInfo->hasResult) {
338,218,924✔
2527
    code = saveTupleData(pCtx, rowIndex, pSrcBlock, &pInfo->pos);
281,730,739✔
2528
  } else if (!noElements) {
56,488,185!
2529
    code = updateTupleData(pCtx, rowIndex, pSrcBlock, &pInfo->pos);
56,768,838✔
2530
  } else {
2531
  }  // dothing
2532

2533
  return code;
337,952,929✔
2534
}
2535

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

2541
  if (IS_VAR_DATA_TYPE(type)) {
193,718,187!
2542
    pInfo->bytes = calcStrBytesByType(type, pData);
49,277,588✔
2543
    // if (type == TSDB_DATA_TYPE_JSON) {
2544
    //   pInfo->bytes = getJsonValueLen(pData);
2545
    // } else {
2546
    //   pInfo->bytes = varDataTLen(pData);
2547
    // }
2548
  }
2549

2550
  (void)memcpy(pInfo->buf, pData, pInfo->bytes);
193,730,420✔
2551
  if (pkData != NULL) {
193,730,420✔
2552
    if (IS_VAR_DATA_TYPE(pInfo->pkType)) {
283,941!
2553
      pInfo->pkBytes = calcStrBytesByType(pInfo->pkType, pkData);
94,102✔
2554
      // if (pInfo->pkType == TSDB_DATA_TYPE_JSON) {
2555
      //   pInfo->pkBytes = getJsonValueLen(pkData);
2556
      // } else {
2557
      //   pInfo->pkBytes = varDataTLen(pkData);
2558
      // }
2559
    }
2560
    (void)memcpy(pInfo->buf + pInfo->bytes, pkData, pInfo->pkBytes);
284,129✔
2561
    pInfo->pkData = pInfo->buf + pInfo->bytes;
284,129✔
2562
  }
2563

2564
  pInfo->ts = currentTs;
193,730,608✔
2565
  int32_t code = firstlastSaveTupleData(pCtx->pSrcBlock, rowIndex, pCtx, pInfo, false);
193,730,608✔
2566
  if (code != TSDB_CODE_SUCCESS) {
193,617,429!
2567
    return code;
×
2568
  }
2569

2570
  pInfo->hasResult = true;
193,617,429✔
2571
  return TSDB_CODE_SUCCESS;
193,617,429✔
2572
}
2573

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

2579
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
81,268,316✔
2580
  SFirstLastRes*       pInfo = GET_ROWCELL_INTERBUF(pResInfo);
81,268,316✔
2581

2582
  SInputColumnInfoData* pInput = &pCtx->input;
81,268,316✔
2583
  SColumnInfoData*      pInputCol = pInput->pData[0];
81,268,316✔
2584

2585
  pInfo->bytes = pInputCol->info.bytes;
81,268,316✔
2586

2587
  if (IS_NULL_TYPE(pInputCol->info.type)) {
81,268,316✔
2588
    return TSDB_CODE_SUCCESS;
8,961✔
2589
  }
2590

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

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

2612
  SColumnDataAgg* pColAgg = (pInput->colDataSMAIsSet) ? pInput->pColumnDataAgg[0] : NULL;
81,260,999!
2613

2614
  TSKEY startKey = getRowPTs(pInput->pPTS, 0);
81,260,999!
2615
  TSKEY endKey = getRowPTs(pInput->pPTS, pInput->totalRows - 1);
81,260,999!
2616

2617
  int32_t blockDataOrder = (startKey <= endKey) ? TSDB_ORDER_ASC : TSDB_ORDER_DESC;
81,260,999✔
2618

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

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

2635
      numOfElems++;
2636

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

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

2658
      numOfElems++;
2659

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

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

2672
  int     from = -1;
81,260,999✔
2673
  int32_t i = -1;
81,260,999✔
2674
  while (funcInputGetNextRowIndex(pInput, from, true, &i, &from)) {
339,723,108✔
2675
    if (pInputCol->hasNull && colDataIsNull(pInputCol, pInput->totalRows, i, pColAgg)) {
351,036,741!
2676
      continue;
4,852,679✔
2677
    }
2678

2679
    numOfElems++;
253,618,786✔
2680
    char* data = colDataGetData(pInputCol, i);
253,618,786!
2681
    char* pkData = NULL;
253,618,786✔
2682
    if (pCtx->hasPrimaryKey) {
253,618,786✔
2683
      pkData = colDataGetData(pkCol, i);
271,652!
2684
    }
2685
    TSKEY cts = pts[i];
253,618,786✔
2686
    if (pResInfo->numOfRes == 0 || pInfo->ts > cts ||
253,618,786✔
2687
        (pInfo->ts == cts && pkCompareFn && pkCompareFn(pkData, pInfo->pkData) < 0)) {
163,933,607!
2688
      int32_t code = doSaveCurrentVal(pCtx, i, cts, pkData, pInputCol->info.type, data);
89,685,179✔
2689
      if (code != TSDB_CODE_SUCCESS) {
89,675,823!
2690
        return code;
×
2691
      }
2692
      pResInfo->numOfRes = 1;
89,675,823✔
2693
    }
2694
  }
2695
#endif
2696

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

2709
int32_t lastFunction(SqlFunctionCtx* pCtx) {
69,312,918✔
2710
  int32_t numOfElems = 0;
69,312,918✔
2711

2712
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
69,312,918✔
2713
  SFirstLastRes*       pInfo = GET_ROWCELL_INTERBUF(pResInfo);
69,312,918✔
2714

2715
  SInputColumnInfoData* pInput = &pCtx->input;
69,312,918✔
2716
  SColumnInfoData*      pInputCol = pInput->pData[0];
69,312,918✔
2717

2718
  int32_t type = pInputCol->info.type;
69,312,918✔
2719
  int32_t bytes = pInputCol->info.bytes;
69,312,918✔
2720

2721
  if (IS_NULL_TYPE(type)) {
69,312,918✔
2722
    return TSDB_CODE_SUCCESS;
8,938✔
2723
  }
2724
  pInfo->bytes = bytes;
69,303,980✔
2725

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

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

2747
  SColumnDataAgg* pColAgg = (pInput->colDataSMAIsSet) ? pInput->pColumnDataAgg[0] : NULL;
69,312,295!
2748

2749
  TSKEY startKey = getRowPTs(pInput->pPTS, 0);
69,312,295!
2750
  TSKEY endKey = getRowPTs(pInput->pPTS, pInput->totalRows - 1);
69,312,295!
2751

2752
  int32_t blockDataOrder = (startKey <= endKey) ? TSDB_ORDER_ASC : TSDB_ORDER_DESC;
69,312,295✔
2753

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

2762
      numOfElems++;
2763

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

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

2778
      numOfElems++;
2779

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

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

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

2806
  // todo refactor
2807
  if (!pInputCol->hasNull && !pCtx->hasPrimaryKey) {
108,721,276✔
2808
    numOfElems = 1;
39,503,269✔
2809

2810
    int32_t round = pInput->numOfRows >> 2;
39,503,269✔
2811
    int32_t reminder = pInput->numOfRows & 0x03;
39,503,269✔
2812

2813
    for (int32_t i = pInput->startRowIndex, tick = 0; tick < round; i += 4, tick += 1) {
67,726,789✔
2814
      int64_t cts = pts[i];
28,257,901✔
2815
      int32_t chosen = i;
28,257,901✔
2816

2817
      if (cts < pts[i + 1]) {
28,257,901✔
2818
        cts = pts[i + 1];
174,767✔
2819
        chosen = i + 1;
174,767✔
2820
      }
2821

2822
      if (cts < pts[i + 2]) {
28,257,901✔
2823
        cts = pts[i + 2];
174,771✔
2824
        chosen = i + 2;
174,771✔
2825
      }
2826

2827
      if (cts < pts[i + 3]) {
28,257,901✔
2828
        cts = pts[i + 3];
174,767✔
2829
        chosen = i + 3;
174,767✔
2830
      }
2831

2832
      if (pResInfo->numOfRes == 0 || pInfo->ts < cts) {
28,257,901✔
2833
        char*   data = colDataGetData(pInputCol, chosen);
2,932,336!
2834
        int32_t code = doSaveCurrentVal(pCtx, chosen, cts, NULL, type, data);
2,932,336✔
2835
        if (code != TSDB_CODE_SUCCESS) {
2,897,955!
2836
          return code;
×
2837
        }
2838
        pResInfo->numOfRes = 1;
2,897,955✔
2839
      }
2840
    }
2841

2842
    for (int32_t i = pInput->startRowIndex + round * 4; i < pInput->startRowIndex + pInput->numOfRows; ++i) {
90,452,046✔
2843
      if (pResInfo->numOfRes == 0 || pInfo->ts < pts[i]) {
51,043,065✔
2844
        char*   data = colDataGetData(pInputCol, i);
35,376,371!
2845
        int32_t code = doSaveCurrentVal(pCtx, i, pts[i], NULL, type, data);
35,376,371✔
2846
        if (code != TSDB_CODE_SUCCESS) {
35,316,464!
2847
          return code;
×
2848
        }
2849
        pResInfo->numOfRes = 1;
35,316,464✔
2850
      }
2851
    }
2852
  } else {
2853
    int     from = -1;
29,809,026✔
2854
    int32_t i = -1;
29,809,026✔
2855
    while (funcInputGetNextRowIndex(pInput, from, false, &i, &from)) {
140,812,947✔
2856
      if (colDataIsNull(pInputCol, pInput->totalRows, i, pColAgg)) {
222,019,062✔
2857
        continue;
8,440,358✔
2858
      }
2859

2860
      numOfElems++;
102,569,173✔
2861
      char* pkData = NULL;
102,569,173✔
2862
      if (pCtx->hasPrimaryKey) {
102,569,173✔
2863
        pkData = colDataGetData(pkCol, i);
306,566!
2864
      }
2865
      if (pResInfo->numOfRes == 0 || pInfo->ts < pts[i] ||
102,569,173✔
2866
          (pInfo->ts == pts[i] && pkCompareFn && pkCompareFn(pkData, pInfo->pkData) < 0)) {
36,824,590!
2867
        char*   data = colDataGetData(pInputCol, i);
65,781,268!
2868
        int32_t code = doSaveCurrentVal(pCtx, i, pts[i], pkData, type, data);
65,781,268✔
2869
        if (code != TSDB_CODE_SUCCESS) {
65,775,658!
2870
          return code;
×
2871
        }
2872
        pResInfo->numOfRes = 1;
65,775,658✔
2873
      }
2874
    }
2875
  }
2876
#endif
2877

2878
#endif
2879

2880
  // save selectivity value for column consisted of all null values
2881
  if (numOfElems == 0) {
69,310,603✔
2882
    int32_t code = firstlastSaveTupleData(pCtx->pSrcBlock, pInput->startRowIndex, pCtx, pInfo, true);
1,319,869✔
2883
    if (code != TSDB_CODE_SUCCESS) {
1,319,869!
2884
      return code;
×
2885
    }
2886
    pInfo->nullTupleSaved = true;
1,319,869✔
2887
  }
2888

2889
  return TSDB_CODE_SUCCESS;
69,310,603✔
2890
}
2891

2892
static bool firstLastTransferInfoImpl(SFirstLastRes* pInput, SFirstLastRes* pOutput, bool isFirst) {
150,867,572✔
2893
  if (!pInput->hasResult) {
150,867,572!
2894
    return false;
×
2895
  }
2896
  __compar_fn_t pkCompareFn = NULL;
150,867,572✔
2897
  if (pInput->pkData) {
150,867,572✔
2898
    pkCompareFn = getKeyComparFunc(pInput->pkType, (isFirst) ? TSDB_ORDER_ASC : TSDB_ORDER_DESC);
9,810✔
2899
  }
2900
  if (pOutput->hasResult) {
150,884,113✔
2901
    if (isFirst) {
38,544,798✔
2902
      if (pInput->ts > pOutput->ts ||
183,707✔
2903
          (pInput->ts == pOutput->ts && pkCompareFn && pkCompareFn(pInput->pkData, pOutput->pkData) > 0)) {
131,550✔
2904
        return false;
52,381✔
2905
      }
2906
    } else {
2907
      if (pInput->ts < pOutput->ts ||
38,361,091✔
2908
          (pInput->ts == pOutput->ts && pkCompareFn && pkCompareFn(pInput->pkData, pOutput->pkData) > 0)) {
18,965,177✔
2909
        return false;
19,398,665✔
2910
      }
2911
    }
2912
  }
2913

2914
  pOutput->isNull = pInput->isNull;
131,433,067✔
2915
  pOutput->ts = pInput->ts;
131,433,067✔
2916
  pOutput->bytes = pInput->bytes;
131,433,067✔
2917
  pOutput->pkType = pInput->pkType;
131,433,067✔
2918

2919
  (void)memcpy(pOutput->buf, pInput->buf, pOutput->bytes);
131,433,067✔
2920
  if (pInput->pkData) {
131,433,067✔
2921
    pOutput->pkBytes = pInput->pkBytes;
9,049✔
2922
    (void)memcpy(pOutput->buf + pOutput->bytes, pInput->pkData, pOutput->pkBytes);
9,049✔
2923
    pOutput->pkData = pOutput->buf + pOutput->bytes;
9,049✔
2924
  }
2925
  return true;
131,433,067✔
2926
}
2927

2928
static int32_t firstLastTransferInfo(SqlFunctionCtx* pCtx, SFirstLastRes* pInput, SFirstLastRes* pOutput, bool isFirst,
150,865,484✔
2929
                                     int32_t rowIndex) {
2930
  if (firstLastTransferInfoImpl(pInput, pOutput, isFirst)) {
150,865,484✔
2931
    int32_t code = firstlastSaveTupleData(pCtx->pSrcBlock, rowIndex, pCtx, pOutput, false);
131,430,424✔
2932
    if (TSDB_CODE_SUCCESS != code) {
131,416,712!
2933
      return code;
×
2934
    }
2935
    pOutput->hasResult = true;
131,416,712✔
2936
  }
2937
  return TSDB_CODE_SUCCESS;
150,857,816✔
2938
}
2939

2940
static int32_t firstLastFunctionMergeImpl(SqlFunctionCtx* pCtx, bool isFirstQuery) {
112,525,032✔
2941
  SInputColumnInfoData* pInput = &pCtx->input;
112,525,032✔
2942
  SColumnInfoData*      pCol = pInput->pData[0];
112,525,032✔
2943

2944
  if (IS_NULL_TYPE(pCol->info.type)) {
112,525,032!
2945
    SET_VAL(GET_RES_INFO(pCtx), 0, 1);
×
2946
    return TSDB_CODE_SUCCESS;
×
2947
  }
2948

2949
  if (pCol->info.type != TSDB_DATA_TYPE_BINARY) {
112,525,032!
2950
    return TSDB_CODE_FUNC_FUNTION_PARA_TYPE;
×
2951
  }
2952

2953
  SFirstLastRes* pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
112,525,032✔
2954

2955
  int32_t start = pInput->startRowIndex;
112,525,032✔
2956
  int32_t numOfElems = 0;
112,525,032✔
2957

2958
  for (int32_t i = start; i < start + pInput->numOfRows; ++i) {
263,381,076✔
2959
    if (colDataIsNull_s(pCol, i)) {
301,779,228✔
2960
      continue;
1,028✔
2961
    }
2962
    char*          data = colDataGetData(pCol, i);
150,888,586!
2963
    SFirstLastRes* pInputInfo = (SFirstLastRes*)varDataVal(data);
150,888,586✔
2964
    if (pCtx->hasPrimaryKey) {
150,888,586✔
2965
      pInputInfo->pkData = pInputInfo->buf + pInputInfo->bytes;
9,810✔
2966
    } else {
2967
      pInputInfo->pkData = NULL;
150,878,776✔
2968
    }
2969

2970
    int32_t code = firstLastTransferInfo(pCtx, pInputInfo, pInfo, isFirstQuery, i);
150,888,586✔
2971
    if (code != TSDB_CODE_SUCCESS) {
150,855,016!
2972
      return code;
×
2973
    }
2974
    if (!numOfElems) {
150,855,016✔
2975
      numOfElems = pInputInfo->hasResult ? 1 : 0;
112,522,019✔
2976
    }
2977
  }
2978

2979
  if (numOfElems == 0) {
112,491,462✔
2980
    int32_t code = firstlastSaveTupleData(pCtx->pSrcBlock, pInput->startRowIndex, pCtx, pInfo, true);
1,028✔
2981
    if (code != TSDB_CODE_SUCCESS) {
1,028!
2982
      return code;
×
2983
    }
2984
    pInfo->nullTupleSaved = true;
1,028✔
2985
  }
2986

2987
  SET_VAL(GET_RES_INFO(pCtx), numOfElems, 1);
112,491,462✔
2988
  return TSDB_CODE_SUCCESS;
112,491,462✔
2989
}
2990

2991
int32_t firstFunctionMerge(SqlFunctionCtx* pCtx) { return firstLastFunctionMergeImpl(pCtx, true); }
27,254,758✔
2992

2993
int32_t lastFunctionMerge(SqlFunctionCtx* pCtx) { return firstLastFunctionMergeImpl(pCtx, false); }
85,290,256✔
2994

2995
int32_t firstLastFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
273,925,565✔
2996
  int32_t          code = TSDB_CODE_SUCCESS;
273,925,565✔
2997
  int32_t          slotId = pCtx->pExpr->base.resSchema.slotId;
273,925,565✔
2998
  SColumnInfoData* pCol = taosArrayGet(pBlock->pDataBlock, slotId);
273,925,565✔
2999
  if (NULL == pCol) {
273,125,278!
3000
    return TSDB_CODE_OUT_OF_RANGE;
×
3001
  }
3002

3003
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
273,125,278✔
3004
  pResInfo->isNullRes = (pResInfo->numOfRes == 0) ? 1 : 0;
273,125,278✔
3005

3006
  SFirstLastRes* pRes = GET_ROWCELL_INTERBUF(pResInfo);
273,125,278✔
3007

3008
  if (pResInfo->isNullRes) {
273,125,278✔
3009
    colDataSetNULL(pCol, pBlock->info.rows);
479,901✔
3010
    return setNullSelectivityValue(pCtx, pBlock, pBlock->info.rows);
479,901✔
3011
  }
3012
  code = colDataSetVal(pCol, pBlock->info.rows, pRes->buf, pRes->isNull || pResInfo->isNullRes);
272,645,377!
3013
  if (TSDB_CODE_SUCCESS != code) {
272,265,789!
3014
    return code;
×
3015
  }
3016

3017
  // handle selectivity
3018
  code = setSelectivityValue(pCtx, pBlock, &pRes->pos, pBlock->info.rows);
272,265,789✔
3019

3020
  return code;
272,210,884✔
3021
}
3022

3023
int32_t firstLastPartialFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
150,320,097✔
3024
  int32_t code = TSDB_CODE_SUCCESS;
150,320,097✔
3025

3026
  SResultRowEntryInfo* pEntryInfo = GET_RES_INFO(pCtx);
150,320,097✔
3027
  SFirstLastRes*       pRes = GET_ROWCELL_INTERBUF(pEntryInfo);
150,320,097✔
3028

3029
  int32_t resultBytes = getFirstLastInfoSize(pRes->bytes, pRes->pkBytes);
150,320,097✔
3030

3031
  // todo check for failure
3032
  char* res = taosMemoryCalloc(resultBytes + VARSTR_HEADER_SIZE, sizeof(char));
150,369,345!
3033
  if (NULL == res) {
150,955,267!
3034
    return terrno;
×
3035
  }
3036
  (void)memcpy(varDataVal(res), pRes, resultBytes);
150,955,267✔
3037

3038
  varDataSetLen(res, resultBytes);
150,955,267✔
3039

3040
  int32_t          slotId = pCtx->pExpr->base.resSchema.slotId;
150,955,267✔
3041
  SColumnInfoData* pCol = taosArrayGet(pBlock->pDataBlock, slotId);
150,955,267✔
3042
  if (NULL == pCol) {
149,645,404!
3043
    taosMemoryFree(res);
×
3044
    return TSDB_CODE_OUT_OF_RANGE;
×
3045
  }
3046

3047
  if (pEntryInfo->numOfRes == 0) {
149,646,018✔
3048
    colDataSetNULL(pCol, pBlock->info.rows);
1,118!
3049
    code = setNullSelectivityValue(pCtx, pBlock, pBlock->info.rows);
1,118✔
3050
  } else {
3051
    code = colDataSetVal(pCol, pBlock->info.rows, res, false);
149,644,900✔
3052
    if (TSDB_CODE_SUCCESS != code) {
148,933,248!
3053
      taosMemoryFree(res);
×
3054
      return code;
×
3055
    }
3056
    code = setSelectivityValue(pCtx, pBlock, &pRes->pos, pBlock->info.rows);
148,933,248✔
3057
  }
3058
  taosMemoryFree(res);
149,149,815!
3059
  return code;
151,106,897✔
3060
}
3061

3062
int32_t lastCombine(SqlFunctionCtx* pDestCtx, SqlFunctionCtx* pSourceCtx) {
×
3063
  SResultRowEntryInfo* pDResInfo = GET_RES_INFO(pDestCtx);
×
3064
  SFirstLastRes*       pDBuf = GET_ROWCELL_INTERBUF(pDResInfo);
×
3065
  int32_t              bytes = pDBuf->bytes;
×
3066

3067
  SResultRowEntryInfo* pSResInfo = GET_RES_INFO(pSourceCtx);
×
3068
  SFirstLastRes*       pSBuf = GET_ROWCELL_INTERBUF(pSResInfo);
×
3069

3070
  pDBuf->hasResult = firstLastTransferInfoImpl(pSBuf, pDBuf, false);
×
3071
  pDResInfo->numOfRes = TMAX(pDResInfo->numOfRes, pSResInfo->numOfRes);
×
3072
  pDResInfo->isNullRes &= pSResInfo->isNullRes;
×
3073
  return TSDB_CODE_SUCCESS;
×
3074
}
3075

3076
static int32_t doSaveLastrow(SqlFunctionCtx* pCtx, char* pData, int32_t rowIndex, int64_t cts, SFirstLastRes* pInfo) {
192,199,670✔
3077
  SInputColumnInfoData* pInput = &pCtx->input;
192,199,670✔
3078
  SColumnInfoData*      pInputCol = pInput->pData[0];
192,199,670✔
3079
  SColumnInfoData*      pkCol = pInput->pPrimaryKey;
192,199,670✔
3080

3081
  if (colDataIsNull_s(pInputCol, rowIndex)) {
384,399,340✔
3082
    pInfo->isNull = true;
9,289✔
3083
  } else {
3084
    pInfo->isNull = false;
192,190,381✔
3085

3086
    if (IS_VAR_DATA_TYPE(pInputCol->info.type)) {
192,190,381!
3087
      pInfo->bytes = calcStrBytesByType(pInputCol->info.type, pData);
18,309,785✔
3088
      // if (pInputCol->info.type == TSDB_DATA_TYPE_JSON) {
3089
      //   pInfo->bytes = getJsonValueLen(pData);
3090
      // } else {
3091
      //   pInfo->bytes = varDataTLen(pData);
3092
      // }
3093
    }
3094

3095
    (void)memcpy(pInfo->buf, pData, pInfo->bytes);
192,198,033✔
3096
  }
3097

3098
  if (pCtx->hasPrimaryKey && !colDataIsNull_s(pkCol, rowIndex)) {
192,223,216✔
3099
    char* pkData = colDataGetData(pkCol, rowIndex);
15,891!
3100
    if (IS_VAR_DATA_TYPE(pInfo->pkType)) {
15,891!
3101
      pInfo->pkBytes = calcStrBytesByType(pInfo->pkType, pkData);
5,296✔
3102
    }
3103
    (void)memcpy(pInfo->buf + pInfo->bytes, pkData, pInfo->pkBytes);
15,887✔
3104
    pInfo->pkData = pInfo->buf + pInfo->bytes;
15,887✔
3105
  }
3106
  pInfo->ts = cts;
192,207,318✔
3107
  int32_t code = firstlastSaveTupleData(pCtx->pSrcBlock, rowIndex, pCtx, pInfo, false);
192,207,318✔
3108
  if (code != TSDB_CODE_SUCCESS) {
192,026,765!
3109
    return code;
×
3110
  }
3111

3112
  pInfo->hasResult = true;
192,026,765✔
3113

3114
  return TSDB_CODE_SUCCESS;
192,026,765✔
3115
}
3116

3117
int32_t lastRowFunction(SqlFunctionCtx* pCtx) {
193,359,241✔
3118
  int32_t numOfElems = 0;
193,359,241✔
3119

3120
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
193,359,241✔
3121
  SFirstLastRes*       pInfo = GET_ROWCELL_INTERBUF(pResInfo);
193,359,241✔
3122

3123
  SInputColumnInfoData* pInput = &pCtx->input;
193,359,241✔
3124
  SColumnInfoData*      pInputCol = pInput->pData[0];
193,359,241✔
3125

3126
  int32_t type = pInputCol->info.type;
193,359,241✔
3127
  int32_t bytes = pInputCol->info.bytes;
193,359,241✔
3128
  pInfo->bytes = bytes;
193,359,241✔
3129

3130
  if (IS_NULL_TYPE(type)) {
193,359,241✔
3131
    return TSDB_CODE_SUCCESS;
93✔
3132
  }
3133
  SColumnInfoData* pkCol = pInput->pPrimaryKey;
193,359,148✔
3134
  pInfo->pkType = -1;
193,359,148✔
3135
  __compar_fn_t pkCompareFn = NULL;
193,359,148✔
3136
  if (pCtx->hasPrimaryKey) {
193,359,148✔
3137
    pInfo->pkType = pkCol->info.type;
17,556✔
3138
    pInfo->pkBytes = pkCol->info.bytes;
17,556✔
3139
    pkCompareFn = getKeyComparFunc(pInfo->pkType, TSDB_ORDER_DESC);
17,556✔
3140
  }
3141
  TSKEY startKey = getRowPTs(pInput->pPTS, 0);
193,458,079✔
3142
  TSKEY endKey = getRowPTs(pInput->pPTS, pInput->totalRows - 1);
193,458,079!
3143

3144
  if (pCtx->order == TSDB_ORDER_ASC && !pCtx->hasPrimaryKey) {
193,458,079!
3145
    for (int32_t i = pInput->numOfRows + pInput->startRowIndex - 1; i >= pInput->startRowIndex; --i) {
210,146,586!
3146
      bool  isNull = colDataIsNull(pInputCol, pInput->numOfRows, i, NULL);
105,082,509✔
3147
      char* data = isNull ? NULL : colDataGetData(pInputCol, i);
105,082,509!
3148
      TSKEY cts = getRowPTs(pInput->pPTS, i);
105,082,509!
3149
      numOfElems++;
105,082,509✔
3150

3151
      if (pResInfo->numOfRes == 0 || pInfo->ts < cts) {
105,082,509✔
3152
        int32_t code = doSaveLastrow(pCtx, data, i, cts, pInfo);
103,466,164✔
3153
        if (code != TSDB_CODE_SUCCESS) return code;
103,451,281!
3154
      }
3155

3156
      break;
105,067,626✔
3157
    }
3158
  } else if (!pCtx->hasPrimaryKey && pCtx->order == TSDB_ORDER_DESC) {
88,379,119!
3159
    // the optimized version only valid if all tuples in one block are monotonious increasing or descreasing.
3160
    // this assumption is NOT always works if project operator exists in downstream.
3161
    for (int32_t i = pInput->startRowIndex; i < pInput->numOfRows + pInput->startRowIndex; ++i) {
176,978,011!
3162
      bool  isNull = colDataIsNull(pInputCol, pInput->numOfRows, i, NULL);
88,628,859✔
3163
      char* data = isNull ? NULL : colDataGetData(pInputCol, i);
88,628,859!
3164
      TSKEY cts = getRowPTs(pInput->pPTS, i);
88,628,859✔
3165
      numOfElems++;
88,628,859✔
3166

3167
      if (pResInfo->numOfRes == 0 || pInfo->ts < cts) {
88,628,859✔
3168
        int32_t code = doSaveLastrow(pCtx, data, i, cts, pInfo);
87,911,678✔
3169
        if (code != TSDB_CODE_SUCCESS) return code;
87,716,199!
3170
      }
3171
      break;
88,433,380✔
3172
    }
3173
  } else {
3174
    int64_t* pts = (int64_t*)pInput->pPTS->pData;
×
3175
    int      from = -1;
×
3176
    int32_t  i = -1;
×
3177
    while (funcInputGetNextRowIndex(pInput, from, false, &i, &from)) {
2,004,183✔
3178
      bool  isNull = colDataIsNull(pInputCol, pInput->numOfRows, i, NULL);
2,169,570✔
3179
      char* data = isNull ? NULL : colDataGetData(pInputCol, i);
2,169,570!
3180
      TSKEY cts = pts[i];
2,169,570✔
3181

3182
      numOfElems++;
2,169,570✔
3183
      char* pkData = NULL;
2,169,570✔
3184
      if (pCtx->hasPrimaryKey) {
2,169,570✔
3185
        pkData = colDataGetData(pkCol, i);
273,907!
3186
      }
3187
      if (pResInfo->numOfRes == 0 || pInfo->ts < cts ||
2,169,570✔
3188
          (pInfo->ts == pts[i] && pkCompareFn && pkCompareFn(pkData, pInfo->pkData) < 0)) {
1,296,958✔
3189
        int32_t code = doSaveLastrow(pCtx, data, i, cts, pInfo);
872,618✔
3190
        if (code != TSDB_CODE_SUCCESS) {
872,744!
3191
          return code;
×
3192
        }
3193
        pResInfo->numOfRes = 1;
872,744✔
3194
      }
3195
    }
3196
  }
3197

3198
  SET_VAL(pResInfo, numOfElems, 1);
193,436,656!
3199
  return TSDB_CODE_SUCCESS;
193,436,656✔
3200
}
3201

3202
bool getDiffFuncEnv(SFunctionNode* UNUSED_PARAM(pFunc), SFuncExecEnv* pEnv) {
107,109✔
3203
  pEnv->calcMemSize = sizeof(SDiffInfo);
107,109✔
3204
  return true;
107,109✔
3205
}
3206

3207
int32_t diffFunctionSetup(SqlFunctionCtx* pCtx, SResultRowEntryInfo* pResInfo) {
4,258,300✔
3208
  if (pResInfo->initialized) {
4,258,300✔
3209
    return TSDB_CODE_SUCCESS;
4,109,261✔
3210
  }
3211
  if (TSDB_CODE_SUCCESS != functionSetup(pCtx, pResInfo)) {
149,039!
3212
    return TSDB_CODE_FUNC_SETUP_ERROR;
×
3213
  }
3214
  SDiffInfo* pDiffInfo = GET_ROWCELL_INTERBUF(pResInfo);
149,039✔
3215
  pDiffInfo->hasPrev = false;
149,039✔
3216
  pDiffInfo->isFirstRow = true;
149,039✔
3217
  pDiffInfo->prev.i64 = 0;
149,039✔
3218
  pDiffInfo->prevTs = -1;
149,039✔
3219
  if (pCtx->numOfParams > 1) {
149,039!
3220
    pDiffInfo->ignoreOption = pCtx->param[1].param.i;  // TODO set correct param
149,039✔
3221
  } else {
3222
    pDiffInfo->ignoreOption = 0;
×
3223
  }
3224
  return TSDB_CODE_SUCCESS;
149,039✔
3225
}
3226

3227
static int32_t doSetPrevVal(SDiffInfo* pDiffInfo, int32_t type, const char* pv, int64_t ts) {
3,245,617✔
3228
  switch (type) {
3,245,617!
3229
    case TSDB_DATA_TYPE_BOOL:
37✔
3230
      pDiffInfo->prev.i64 = *(bool*)pv ? 1 : 0;
37✔
3231
      break;
37✔
3232
    case TSDB_DATA_TYPE_UTINYINT:
1,163,359✔
3233
    case TSDB_DATA_TYPE_TINYINT:
3234
      pDiffInfo->prev.i64 = *(int8_t*)pv;
1,163,359✔
3235
      break;
1,163,359✔
3236
    case TSDB_DATA_TYPE_UINT:
42,851✔
3237
    case TSDB_DATA_TYPE_INT:
3238
      pDiffInfo->prev.i64 = *(int32_t*)pv;
42,851✔
3239
      break;
42,851✔
3240
    case TSDB_DATA_TYPE_USMALLINT:
158,431✔
3241
    case TSDB_DATA_TYPE_SMALLINT:
3242
      pDiffInfo->prev.i64 = *(int16_t*)pv;
158,431✔
3243
      break;
158,431✔
3244
    case TSDB_DATA_TYPE_TIMESTAMP:
617✔
3245
    case TSDB_DATA_TYPE_UBIGINT:
3246
    case TSDB_DATA_TYPE_BIGINT:
3247
      pDiffInfo->prev.i64 = *(int64_t*)pv;
617✔
3248
      break;
617✔
3249
    case TSDB_DATA_TYPE_FLOAT:
660,878✔
3250
      pDiffInfo->prev.d64 = *(float*)pv;
660,878✔
3251
      break;
660,878✔
3252
    case TSDB_DATA_TYPE_DOUBLE:
1,219,444✔
3253
      pDiffInfo->prev.d64 = *(double*)pv;
1,219,444✔
3254
      break;
1,219,444✔
3255
    default:
×
3256
      return TSDB_CODE_FUNC_FUNTION_PARA_TYPE;
×
3257
  }
3258
  pDiffInfo->prevTs = ts;
3,245,617✔
3259
  pDiffInfo->hasPrev = true;
3,245,617✔
3260
  return TSDB_CODE_SUCCESS;
3,245,617✔
3261
}
3262

3263
static bool diffIsNegtive(SDiffInfo* pDiffInfo, int32_t type, const char* pv) {
13,364,196✔
3264
  switch (type) {
13,364,196!
3265
    case TSDB_DATA_TYPE_UINT: {
×
3266
      int64_t v = *(uint32_t*)pv;
×
3267
      return v < pDiffInfo->prev.i64;
×
3268
    }
3269
    case TSDB_DATA_TYPE_INT: {
3,333✔
3270
      int64_t v = *(int32_t*)pv;
3,333✔
3271
      return v < pDiffInfo->prev.i64;
3,333✔
3272
    }
3273
    case TSDB_DATA_TYPE_BOOL: {
×
3274
      int64_t v = *(bool*)pv;
×
3275
      return v < pDiffInfo->prev.i64;
×
3276
    }
3277
    case TSDB_DATA_TYPE_UTINYINT: {
×
3278
      int64_t v = *(uint8_t*)pv;
×
3279
      return v < pDiffInfo->prev.i64;
×
3280
    }
3281
    case TSDB_DATA_TYPE_TINYINT: {
4,992,946✔
3282
      int64_t v = *(int8_t*)pv;
4,992,946✔
3283
      return v < pDiffInfo->prev.i64;
4,992,946✔
3284
    }
3285
    case TSDB_DATA_TYPE_USMALLINT: {
×
3286
      int64_t v = *(uint16_t*)pv;
×
3287
      return v < pDiffInfo->prev.i64;
×
3288
    }
3289
    case TSDB_DATA_TYPE_SMALLINT: {
825,687✔
3290
      int64_t v = *(int16_t*)pv;
825,687✔
3291
      return v < pDiffInfo->prev.i64;
825,687✔
3292
    }
3293
    case TSDB_DATA_TYPE_UBIGINT: {
40✔
3294
      uint64_t v = *(uint64_t*)pv;
40✔
3295
      return v < (uint64_t)pDiffInfo->prev.i64;
40✔
3296
    }
3297
    case TSDB_DATA_TYPE_TIMESTAMP:
3,414✔
3298
    case TSDB_DATA_TYPE_BIGINT: {
3299
      int64_t v = *(int64_t*)pv;
3,414✔
3300
      return v < pDiffInfo->prev.i64;
3,414✔
3301
    }
3302
    case TSDB_DATA_TYPE_FLOAT: {
1,935,754✔
3303
      float v = *(float*)pv;
1,935,754✔
3304
      return v < pDiffInfo->prev.d64;
1,935,754✔
3305
    }
3306
    case TSDB_DATA_TYPE_DOUBLE: {
5,603,022✔
3307
      double v = *(double*)pv;
5,603,022✔
3308
      return v < pDiffInfo->prev.d64;
5,603,022✔
3309
    }
3310
    default:
×
3311
      return false;
×
3312
  }
3313

3314
  return false;
3315
}
3316

3317
static void tryToSetInt64(SDiffInfo* pDiffInfo, int32_t type, SColumnInfoData* pOutput, int64_t v, int32_t pos) {
2,147,483,647✔
3318
  bool isNegative = v < pDiffInfo->prev.i64;
2,147,483,647✔
3319
  if (type == TSDB_DATA_TYPE_UBIGINT) {
2,147,483,647✔
3320
    isNegative = (uint64_t)v < (uint64_t)pDiffInfo->prev.i64;
1,353✔
3321
  }
3322
  int64_t delta = v - pDiffInfo->prev.i64;
2,147,483,647✔
3323
  if (isNegative && ignoreNegative(pDiffInfo->ignoreOption)) {
2,147,483,647✔
3324
    colDataSetNull_f_s(pOutput, pos);
1,587,901✔
3325
    pOutput->hasNull = true;
1,587,901✔
3326
  } else {
3327
    colDataSetInt64(pOutput, pos, &delta);
2,147,483,647✔
3328
  }
3329
  pDiffInfo->prev.i64 = v;
2,147,483,647✔
3330
}
2,147,483,647✔
3331

3332
static void tryToSetDouble(SDiffInfo* pDiffInfo, SColumnInfoData* pOutput, double v, int32_t pos) {
7,414,375✔
3333
  double delta = v - pDiffInfo->prev.d64;
7,414,375✔
3334
  if (delta < 0 && ignoreNegative(pDiffInfo->ignoreOption)) {
7,414,375✔
3335
    colDataSetNull_f_s(pOutput, pos);
1,952,402✔
3336
  } else {
3337
    colDataSetDouble(pOutput, pos, &delta);
5,461,973✔
3338
  }
3339
  pDiffInfo->prev.d64 = v;
7,414,375✔
3340
}
7,414,375✔
3341

3342
static int32_t doHandleDiff(SDiffInfo* pDiffInfo, int32_t type, const char* pv, SColumnInfoData* pOutput, int32_t pos,
2,147,483,647✔
3343
                            int64_t ts) {
3344
  if (!pDiffInfo->hasPrev) {
2,147,483,647✔
3345
    colDataSetNull_f_s(pOutput, pos);
500✔
3346
    return doSetPrevVal(pDiffInfo, type, pv, ts);
500✔
3347
  }
3348
  pDiffInfo->prevTs = ts;
2,147,483,647✔
3349
  switch (type) {
2,147,483,647!
3350
    case TSDB_DATA_TYPE_UINT: {
1,283✔
3351
      int64_t v = *(uint32_t*)pv;
1,283✔
3352
      tryToSetInt64(pDiffInfo, type, pOutput, v, pos);
1,283✔
3353
      break;
1,283✔
3354
    }
3355
    case TSDB_DATA_TYPE_INT: {
20,975,767✔
3356
      int64_t v = *(int32_t*)pv;
20,975,767✔
3357
      tryToSetInt64(pDiffInfo, type, pOutput, v, pos);
20,975,767✔
3358
      break;
20,975,767✔
3359
    }
3360
    case TSDB_DATA_TYPE_BOOL: {
878✔
3361
      int64_t v = *(bool*)pv;
878✔
3362
      tryToSetInt64(pDiffInfo, type, pOutput, v, pos);
878✔
3363
      break;
878✔
3364
    }
3365
    case TSDB_DATA_TYPE_UTINYINT: {
675✔
3366
      int64_t v = *(uint8_t*)pv;
675✔
3367
      tryToSetInt64(pDiffInfo, type, pOutput, v, pos);
675✔
3368
      break;
675✔
3369
    }
3370
    case TSDB_DATA_TYPE_TINYINT: {
4,245,567✔
3371
      int64_t v = *(int8_t*)pv;
4,245,567✔
3372
      tryToSetInt64(pDiffInfo, type, pOutput, v, pos);
4,245,567✔
3373
      break;
4,245,567✔
3374
    }
3375
    case TSDB_DATA_TYPE_USMALLINT: {
675✔
3376
      int64_t v = *(uint16_t*)pv;
675✔
3377
      tryToSetInt64(pDiffInfo, type, pOutput, v, pos);
675✔
3378
      break;
675✔
3379
    }
3380
    case TSDB_DATA_TYPE_SMALLINT: {
821,567✔
3381
      int64_t v = *(int16_t*)pv;
821,567✔
3382
      tryToSetInt64(pDiffInfo, type, pOutput, v, pos);
821,567✔
3383
      break;
821,567✔
3384
    }
3385
    case TSDB_DATA_TYPE_TIMESTAMP:
2,147,483,647✔
3386
    case TSDB_DATA_TYPE_UBIGINT:
3387
    case TSDB_DATA_TYPE_BIGINT: {
3388
      int64_t v = *(int64_t*)pv;
2,147,483,647✔
3389
      tryToSetInt64(pDiffInfo, type, pOutput, v, pos);
2,147,483,647✔
3390
      break;
2,147,483,647✔
3391
    }
3392
    case TSDB_DATA_TYPE_FLOAT: {
1,427,420✔
3393
      double v = *(float*)pv;
1,427,420✔
3394
      tryToSetDouble(pDiffInfo, pOutput, v, pos);
1,427,420✔
3395
      break;
1,427,420✔
3396
    }
3397
    case TSDB_DATA_TYPE_DOUBLE: {
5,986,955✔
3398
      double v = *(double*)pv;
5,986,955✔
3399
      tryToSetDouble(pDiffInfo, pOutput, v, pos);
5,986,955✔
3400
      break;
5,986,955✔
3401
    }
3402
    default:
×
3403
      return TSDB_CODE_FUNC_FUNTION_PARA_TYPE;
×
3404
  }
3405
  pDiffInfo->hasPrev = true;
2,147,483,647✔
3406
  return TSDB_CODE_SUCCESS;
2,147,483,647✔
3407
}
3408

3409
// TODO: the primary key compare can be skipped for ordered pk if knonwn before
3410
// TODO: for desc ordered, pk shall select the smallest one for one ts. if across block boundaries.
3411
bool funcInputGetNextRowIndex(SInputColumnInfoData* pInput, int32_t from, bool firstOccur, int32_t* pRowIndex,
482,663,570✔
3412
                              int32_t* nextFrom) {
3413
  if (pInput->pPrimaryKey == NULL) {
482,663,570✔
3414
    if (from == -1) {
481,767,645✔
3415
      from = pInput->startRowIndex;
111,163,965✔
3416
    } else if (from >= pInput->numOfRows + pInput->startRowIndex) {
370,603,680✔
3417
      return false;
111,135,596✔
3418
    }
3419
    *pRowIndex = from;
370,632,049✔
3420
    *nextFrom = from + 1;
370,632,049✔
3421
    return true;
370,632,049✔
3422
  } else {
3423
    if (from == -1) {
895,925✔
3424
      from = pInput->startRowIndex;
55,076✔
3425
    } else if (from >= pInput->numOfRows + pInput->startRowIndex) {
840,849✔
3426
      return false;
55,063✔
3427
    }
3428
    TSKEY*           tsList = (int64_t*)pInput->pPTS->pData;
840,862✔
3429
    SColumnInfoData* pkCol = pInput->pPrimaryKey;
840,862✔
3430
    int8_t           pkType = pkCol->info.type;
840,862✔
3431
    int32_t          order = (firstOccur) ? TSDB_ORDER_ASC : TSDB_ORDER_DESC;
840,862✔
3432
    __compar_fn_t    compareFunc = getKeyComparFunc(pkType, order);
840,862✔
3433
    int32_t          select = from;
847,662✔
3434
    char*            val = colDataGetData(pkCol, select);
847,662!
3435
    while (from < pInput->numOfRows + pInput->startRowIndex - 1 && tsList[from + 1] == tsList[from]) {
2,118,527✔
3436
      char* val1 = colDataGetData(pkCol, from + 1);
1,271,453!
3437
      if (compareFunc(val1, val) < 0) {
1,271,453✔
3438
        select = from + 1;
393,674✔
3439
        val = val1;
393,674✔
3440
      }
3441
      from = from + 1;
1,270,865✔
3442
    }
3443
    *pRowIndex = select;
847,074✔
3444
    *nextFrom = from + 1;
847,074✔
3445
    return true;
847,074✔
3446
  }
3447
}
3448

3449
bool getForecastConfEnv(SFunctionNode* UNUSED_PARAM(pFunc), SFuncExecEnv* pEnv) {
×
3450
  pEnv->calcMemSize = sizeof(double);
×
3451
  return true;
×
3452
}
3453

3454
int32_t diffResultIsNull(SqlFunctionCtx* pCtx, SFuncInputRow* pRow) {
2,147,483,647✔
3455
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
2,147,483,647✔
3456
  SDiffInfo*           pDiffInfo = GET_ROWCELL_INTERBUF(pResInfo);
2,147,483,647✔
3457

3458
  if (pRow->isDataNull || !pDiffInfo->hasPrev) {
2,147,483,647✔
3459
    return true;
197,754✔
3460
  } else if (ignoreNegative(pDiffInfo->ignoreOption)) {
2,147,483,647✔
3461
    return diffIsNegtive(pDiffInfo, pCtx->input.pData[0]->info.type, pRow->pData);
13,337,603✔
3462
  }
3463
  return false;
2,147,483,647✔
3464
}
3465

3466
bool isFirstRow(SqlFunctionCtx* pCtx, SFuncInputRow* pRow) {
2,147,483,647✔
3467
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
2,147,483,647✔
3468
  SDiffInfo*           pDiffInfo = GET_ROWCELL_INTERBUF(pResInfo);
2,147,483,647✔
3469
  return pDiffInfo->isFirstRow;
2,147,483,647✔
3470
}
3471

3472
int32_t trySetPreVal(SqlFunctionCtx* pCtx, SFuncInputRow* pRow) {
3,246,415✔
3473
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
3,246,415✔
3474
  SDiffInfo*           pDiffInfo = GET_ROWCELL_INTERBUF(pResInfo);
3,246,415✔
3475
  pDiffInfo->isFirstRow = false;
3,246,415✔
3476
  if (pRow->isDataNull) {
3,246,415✔
3477
    return TSDB_CODE_SUCCESS;
1,298✔
3478
  }
3479

3480
  SInputColumnInfoData* pInput = &pCtx->input;
3,245,117✔
3481
  SColumnInfoData*      pInputCol = pInput->pData[0];
3,245,117✔
3482
  int8_t                inputType = pInputCol->info.type;
3,245,117✔
3483

3484
  char* pv = pRow->pData;
3,245,117✔
3485
  return doSetPrevVal(pDiffInfo, inputType, pv, pRow->ts);
3,245,117✔
3486
}
3487

3488
int32_t setDoDiffResult(SqlFunctionCtx* pCtx, SFuncInputRow* pRow, int32_t pos) {
2,147,483,647✔
3489
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
2,147,483,647✔
3490
  SDiffInfo*           pDiffInfo = GET_ROWCELL_INTERBUF(pResInfo);
2,147,483,647✔
3491

3492
  SInputColumnInfoData* pInput = &pCtx->input;
2,147,483,647✔
3493
  SColumnInfoData*      pInputCol = pInput->pData[0];
2,147,483,647✔
3494
  int8_t                inputType = pInputCol->info.type;
2,147,483,647✔
3495
  SColumnInfoData*      pOutput = (SColumnInfoData*)pCtx->pOutput;
2,147,483,647✔
3496
  int32_t               code = TSDB_CODE_SUCCESS;
2,147,483,647✔
3497
  if (pRow->isDataNull) {
2,147,483,647✔
3498
    colDataSetNull_f_s(pOutput, pos);
48,926✔
3499
    pOutput->hasNull = true;
48,926✔
3500

3501
    // handle selectivity
3502
    if (pCtx->subsidiaries.num > 0) {
48,926✔
3503
      code = appendSelectivityCols(pCtx, pRow->block, pRow->rowIndex, pos);
203✔
3504
      if (code != TSDB_CODE_SUCCESS) {
203!
3505
        return code;
×
3506
      }
3507
    }
3508
    return TSDB_CODE_SUCCESS;
48,926✔
3509
  }
3510

3511
  char* pv = pRow->pData;
2,147,483,647✔
3512

3513
  if (pRow->ts == pDiffInfo->prevTs) {
2,147,483,647✔
3514
    return TSDB_CODE_FUNC_DUP_TIMESTAMP;
22✔
3515
  }
3516
  code = doHandleDiff(pDiffInfo, inputType, pv, pOutput, pos, pRow->ts);
2,147,483,647✔
3517
  if (code != TSDB_CODE_SUCCESS) {
2,147,483,647!
3518
    return code;
×
3519
  }
3520
  // handle selectivity
3521
  if (pCtx->subsidiaries.num > 0) {
2,147,483,647✔
3522
    code = appendSelectivityCols(pCtx, pRow->block, pRow->rowIndex, pos);
36,434,705✔
3523
    if (code != TSDB_CODE_SUCCESS) {
36,434,705!
3524
      return code;
×
3525
    }
3526
  }
3527

3528
  return TSDB_CODE_SUCCESS;
2,147,483,647✔
3529
}
3530

3531
int32_t diffFunction(SqlFunctionCtx* pCtx) { return TSDB_CODE_SUCCESS; }
4,151,191✔
3532

3533
int32_t diffFunctionByRow(SArray* pCtxArray) {
4,150,951✔
3534
  int32_t code = TSDB_CODE_SUCCESS;
4,150,951✔
3535
  int     diffColNum = pCtxArray->size;
4,150,951✔
3536
  if (diffColNum == 0) {
4,150,951!
3537
    return TSDB_CODE_SUCCESS;
×
3538
  }
3539
  int32_t numOfElems = 0;
4,150,951✔
3540

3541
  SArray* pRows = taosArrayInit_s(sizeof(SFuncInputRow), diffColNum);
4,150,951✔
3542
  if (NULL == pRows) {
4,150,952!
3543
    return terrno;
×
3544
  }
3545

3546
  bool keepNull = false;
4,150,952✔
3547
  for (int i = 0; i < diffColNum; ++i) {
8,302,142✔
3548
    SqlFunctionCtx* pCtx = *(SqlFunctionCtx**)taosArrayGet(pCtxArray, i);
4,151,191✔
3549
    if (NULL == pCtx) {
4,151,190!
3550
      code = terrno;
×
3551
      goto _exit;
×
3552
    }
3553
    funcInputUpdate(pCtx);
4,151,190✔
3554
    SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
4,151,190✔
3555
    SDiffInfo*           pDiffInfo = GET_ROWCELL_INTERBUF(pResInfo);
4,151,190✔
3556
    if (!ignoreNull(pDiffInfo->ignoreOption)) {
4,151,190✔
3557
      keepNull = true;
4,098,292✔
3558
    }
3559
  }
3560

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

3600
    bool newRow = false;
2,147,483,647✔
3601
    for (int i = 0; i < diffColNum; ++i) {
2,147,483,647✔
3602
      SqlFunctionCtx* pCtx = *(SqlFunctionCtx**)taosArrayGet(pCtxArray, i);
2,147,483,647✔
3603
      SFuncInputRow*  pRow = (SFuncInputRow*)taosArrayGet(pRows, i);
2,147,483,647✔
3604
      if (NULL == pCtx || NULL == pRow) {
2,147,483,647!
3605
        code = terrno;
×
3606
        goto _exit;
×
3607
      }
3608
      if ((keepNull || hasNotNullValue) && !isFirstRow(pCtx, pRow)) {
2,147,483,647✔
3609
        code = setDoDiffResult(pCtx, pRow, pos);
2,147,483,647✔
3610
        if (code != TSDB_CODE_SUCCESS) {
2,147,483,647✔
3611
          goto _exit;
22✔
3612
        }
3613
        newRow = true;
2,147,483,647✔
3614
      } else {
3615
        code = trySetPreVal(pCtx, pRow);
3,245,946✔
3616
        if (code != TSDB_CODE_SUCCESS) {
3,246,415!
3617
          goto _exit;
×
3618
        }
3619
      }
3620
    }
3621
    if (newRow) ++numOfElems;
2,147,483,647✔
3622
  }
3623

3624
  for (int i = 0; i < diffColNum; ++i) {
8,302,095✔
3625
    SqlFunctionCtx* pCtx = *(SqlFunctionCtx**)taosArrayGet(pCtxArray, i);
4,151,165✔
3626
    if (NULL == pCtx) {
4,151,165!
3627
      code = terrno;
×
3628
      goto _exit;
×
3629
    }
3630
    SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
4,151,165✔
3631
    pResInfo->numOfRes = numOfElems;
4,151,165✔
3632
  }
3633

3634
_exit:
4,150,930✔
3635
  if (pRows) {
4,150,952!
3636
    taosArrayDestroy(pRows);
4,150,952✔
3637
    pRows = NULL;
4,150,952✔
3638
  }
3639
  return code;
4,150,952✔
3640
}
3641

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

3644
bool getTopBotFuncEnv(SFunctionNode* pFunc, SFuncExecEnv* pEnv) {
221,623✔
3645
  SValueNode* pkNode = (SValueNode*)nodesListGetNode(pFunc->pParameterList, 1);
221,623✔
3646
  pEnv->calcMemSize = sizeof(STopBotRes) + pkNode->datum.i * sizeof(STopBotResItem);
221,709✔
3647
  return true;
221,709✔
3648
}
3649

3650
int32_t topBotFunctionSetup(SqlFunctionCtx* pCtx, SResultRowEntryInfo* pResInfo) {
101,771,383✔
3651
  if (pResInfo->initialized) {
101,771,383!
3652
    return TSDB_CODE_SUCCESS;
×
3653
  }
3654
  if (TSDB_CODE_SUCCESS != functionSetup(pCtx, pResInfo)) {
101,771,383!
3655
    return TSDB_CODE_FUNC_SETUP_ERROR;
×
3656
  }
3657

3658
  STopBotRes*           pRes = GET_ROWCELL_INTERBUF(pResInfo);
101,849,447✔
3659
  SInputColumnInfoData* pInput = &pCtx->input;
101,849,447✔
3660

3661
  pRes->maxSize = pCtx->param[1].param.i;
101,849,447✔
3662

3663
  pRes->nullTupleSaved = false;
101,849,447✔
3664
  pRes->nullTuplePos.pageId = -1;
101,849,447✔
3665
  return TSDB_CODE_SUCCESS;
101,849,447✔
3666
}
3667

3668
static STopBotRes* getTopBotOutputInfo(SqlFunctionCtx* pCtx) {
442,055,315✔
3669
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
442,055,315✔
3670
  STopBotRes*          pRes = GET_ROWCELL_INTERBUF(pResInfo);
442,055,315✔
3671
  pRes->pItems = (STopBotResItem*)((char*)pRes + sizeof(STopBotRes));
442,055,315✔
3672

3673
  return pRes;
442,055,315✔
3674
}
3675

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

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

3681
int32_t topFunction(SqlFunctionCtx* pCtx) {
56,770,053✔
3682
  int32_t              numOfElems = 0;
56,770,053✔
3683
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
56,770,053✔
3684

3685
  SInputColumnInfoData* pInput = &pCtx->input;
56,770,053✔
3686
  SColumnInfoData*      pCol = pInput->pData[0];
56,770,053✔
3687

3688
  STopBotRes* pRes = getTopBotOutputInfo(pCtx);
56,770,053✔
3689
  pRes->type = pInput->pData[0]->info.type;
56,767,986✔
3690

3691
  int32_t start = pInput->startRowIndex;
56,767,986✔
3692
  for (int32_t i = start; i < pInput->numOfRows + start; ++i) {
200,799,803✔
3693
    if (pCol->hasNull && colDataIsNull_f(pCol, i)) {
143,951,781!
3694
      continue;
27,629✔
3695
    }
3696

3697
    numOfElems++;
143,924,152✔
3698
    char*   data = colDataGetData(pCol, i);
143,924,152!
3699
    int32_t code = doAddIntoResult(pCtx, data, i, pCtx->pSrcBlock, pRes->type, pInput->uid, pResInfo, true);
143,924,152✔
3700
    if (code != TSDB_CODE_SUCCESS) {
144,004,188!
3701
      return code;
×
3702
    }
3703
  }
3704

3705
  if (numOfElems == 0 && pCtx->subsidiaries.num > 0 && !pRes->nullTupleSaved) {
56,848,022✔
3706
    int32_t code = saveTupleData(pCtx, pInput->startRowIndex, pCtx->pSrcBlock, &pRes->nullTuplePos);
4,181✔
3707
    if (code != TSDB_CODE_SUCCESS) {
4,181!
3708
      return code;
×
3709
    }
3710
    pRes->nullTupleSaved = true;
4,181✔
3711
  }
3712
  return TSDB_CODE_SUCCESS;
56,848,022✔
3713
}
3714

3715
int32_t bottomFunction(SqlFunctionCtx* pCtx) {
45,939,427✔
3716
  int32_t              numOfElems = 0;
45,939,427✔
3717
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
45,939,427✔
3718

3719
  SInputColumnInfoData* pInput = &pCtx->input;
45,939,427✔
3720
  SColumnInfoData*      pCol = pInput->pData[0];
45,939,427✔
3721

3722
  STopBotRes* pRes = getTopBotOutputInfo(pCtx);
45,939,427✔
3723
  pRes->type = pInput->pData[0]->info.type;
45,938,764✔
3724

3725
  int32_t start = pInput->startRowIndex;
45,938,764✔
3726
  for (int32_t i = start; i < pInput->numOfRows + start; ++i) {
140,539,365✔
3727
    if (pCol->hasNull && colDataIsNull_f(pCol, i)) {
94,587,927!
3728
      continue;
19,101✔
3729
    }
3730

3731
    numOfElems++;
94,568,826✔
3732
    char*   data = colDataGetData(pCol, i);
94,568,826!
3733
    int32_t code = doAddIntoResult(pCtx, data, i, pCtx->pSrcBlock, pRes->type, pInput->uid, pResInfo, false);
94,568,826✔
3734
    if (code != TSDB_CODE_SUCCESS) {
94,581,500!
3735
      return code;
×
3736
    }
3737
  }
3738

3739
  if (numOfElems == 0 && pCtx->subsidiaries.num > 0 && !pRes->nullTupleSaved) {
45,951,438✔
3740
    int32_t code = saveTupleData(pCtx, pInput->startRowIndex, pCtx->pSrcBlock, &pRes->nullTuplePos);
3,318✔
3741
    if (code != TSDB_CODE_SUCCESS) {
3,318!
3742
      return code;
×
3743
    }
3744
    pRes->nullTupleSaved = true;
3,318✔
3745
  }
3746

3747
  return TSDB_CODE_SUCCESS;
45,951,438✔
3748
}
3749

3750
static int32_t topBotResComparFn(const void* p1, const void* p2, const void* param) {
948,653,701✔
3751
  uint16_t type = *(uint16_t*)param;
948,653,701✔
3752

3753
  STopBotResItem* val1 = (STopBotResItem*)p1;
948,653,701✔
3754
  STopBotResItem* val2 = (STopBotResItem*)p2;
948,653,701✔
3755

3756
  if (IS_SIGNED_NUMERIC_TYPE(type)) {
948,653,701!
3757
    if (val1->v.i == val2->v.i) {
593,300,343✔
3758
      return 0;
224,675✔
3759
    }
3760

3761
    return (val1->v.i > val2->v.i) ? 1 : -1;
593,075,668✔
3762
  } else if (IS_UNSIGNED_NUMERIC_TYPE(type)) {
355,353,358!
3763
    if (val1->v.u == val2->v.u) {
735,882✔
3764
      return 0;
155,759✔
3765
    }
3766

3767
    return (val1->v.u > val2->v.u) ? 1 : -1;
580,123✔
3768
  } else if (TSDB_DATA_TYPE_FLOAT == type) {
354,617,476✔
3769
    if (val1->v.f == val2->v.f) {
307,523,551✔
3770
      return 0;
63✔
3771
    }
3772

3773
    return (val1->v.f > val2->v.f) ? 1 : -1;
307,523,488✔
3774
  }
3775

3776
  if (val1->v.d == val2->v.d) {
47,093,925✔
3777
    return 0;
11✔
3778
  }
3779

3780
  return (val1->v.d > val2->v.d) ? 1 : -1;
47,093,914✔
3781
}
3782

3783
int32_t doAddIntoResult(SqlFunctionCtx* pCtx, void* pData, int32_t rowIndex, SSDataBlock* pSrcBlock, uint16_t type,
238,473,411✔
3784
                        uint64_t uid, SResultRowEntryInfo* pEntryInfo, bool isTopQuery) {
3785
  STopBotRes* pRes = getTopBotOutputInfo(pCtx);
238,473,411✔
3786
  int32_t     code = TSDB_CODE_SUCCESS;
238,434,121✔
3787

3788
  SVariant val = {0};
238,434,121✔
3789
  TAOS_CHECK_RETURN(taosVariantCreateFromBinary(&val, pData, tDataTypes[type].bytes, type));
238,434,121!
3790

3791
  STopBotResItem* pItems = pRes->pItems;
238,546,822✔
3792

3793
  // not full yet
3794
  if (pEntryInfo->numOfRes < pRes->maxSize) {
238,546,822✔
3795
    STopBotResItem* pItem = &pItems[pEntryInfo->numOfRes];
156,021,902✔
3796
    pItem->v = val;
156,021,902✔
3797
    pItem->uid = uid;
156,021,902✔
3798

3799
    // save the data of this tuple
3800
    if (pCtx->subsidiaries.num > 0) {
156,021,902✔
3801
      code = saveTupleData(pCtx, rowIndex, pSrcBlock, &pItem->tuplePos);
81,886,621✔
3802
      if (code != TSDB_CODE_SUCCESS) {
81,838,004!
3803
        return code;
×
3804
      }
3805
    }
3806
#ifdef BUF_PAGE_DEBUG
3807
    qDebug("page_saveTuple i:%d, item:%p,pageId:%d, offset:%d\n", pEntryInfo->numOfRes, pItem, pItem->tuplePos.pageId,
3808
           pItem->tuplePos.offset);
3809
#endif
3810
    // allocate the buffer and keep the data of this row into the new allocated buffer
3811
    pEntryInfo->numOfRes++;
155,973,285✔
3812
    code = taosheapsort((void*)pItems, sizeof(STopBotResItem), pEntryInfo->numOfRes, (const void*)&type,
155,973,285✔
3813
                        topBotResComparFn, !isTopQuery);
155,973,285✔
3814
    if (code != TSDB_CODE_SUCCESS) {
156,096,608!
3815
      return code;
×
3816
    }
3817
  } else {  // replace the minimum value in the result
3818
    if ((isTopQuery && ((IS_SIGNED_NUMERIC_TYPE(type) && val.i > pItems[0].v.i) ||
82,524,920✔
3819
                        (IS_UNSIGNED_NUMERIC_TYPE(type) && val.u > pItems[0].v.u) ||
48,268,206!
3820
                        (TSDB_DATA_TYPE_FLOAT == type && val.f > pItems[0].v.f) ||
48,176,748✔
3821
                        (TSDB_DATA_TYPE_DOUBLE == type && val.d > pItems[0].v.d))) ||
43,293,005✔
3822
        (!isTopQuery && ((IS_SIGNED_NUMERIC_TYPE(type) && val.i < pItems[0].v.i) ||
69,905,071!
3823
                         (IS_UNSIGNED_NUMERIC_TYPE(type) && val.u < pItems[0].v.u) ||
22,083,544!
3824
                         (TSDB_DATA_TYPE_FLOAT == type && val.f < pItems[0].v.f) ||
22,081,424✔
3825
                         (TSDB_DATA_TYPE_DOUBLE == type && val.d < pItems[0].v.d)))) {
20,869,241✔
3826
      // replace the old data and the coresponding tuple data
3827
      STopBotResItem* pItem = &pItems[0];
19,711,260✔
3828
      pItem->v = val;
19,711,260✔
3829
      pItem->uid = uid;
19,711,260✔
3830

3831
      // save the data of this tuple by over writing the old data
3832
      if (pCtx->subsidiaries.num > 0) {
19,711,260✔
3833
        code = updateTupleData(pCtx, rowIndex, pSrcBlock, &pItem->tuplePos);
13,027,217✔
3834
        if (code != TSDB_CODE_SUCCESS) {
13,023,534!
3835
          return code;
×
3836
        }
3837
      }
3838
#ifdef BUF_PAGE_DEBUG
3839
      qDebug("page_copyTuple pageId:%d, offset:%d", pItem->tuplePos.pageId, pItem->tuplePos.offset);
3840
#endif
3841
      code = taosheapadjust((void*)pItems, sizeof(STopBotResItem), 0, pEntryInfo->numOfRes - 1, (const void*)&type,
19,707,577✔
3842
                            topBotResComparFn, NULL, !isTopQuery);
19,707,577✔
3843
      if (code != TSDB_CODE_SUCCESS) {
19,638,432!
3844
        return code;
×
3845
      }
3846
    }
3847
  }
3848

3849
  return TSDB_CODE_SUCCESS;
238,548,700✔
3850
}
3851

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

3863
  int32_t offset = 0;
590,713,730✔
3864
  for (int32_t i = 0; i < pSubsidiaryies->num; ++i) {
1,178,484,444✔
3865
    SqlFunctionCtx* pc = pSubsidiaryies->pCtx[i];
590,760,252✔
3866

3867
    // group_key function has its own process function
3868
    // do not process there
3869
    if (fmIsGroupKeyFunc(pc->functionId)) {
590,760,252!
3870
      continue;
×
3871
    }
3872

3873
    SFunctParam* pFuncParam = &pc->pExpr->base.pParam[0];
590,691,766✔
3874
    int32_t      srcSlotId = pFuncParam->pCol->slotId;
590,691,766✔
3875

3876
    SColumnInfoData* pCol = taosArrayGet(pSrcBlock->pDataBlock, srcSlotId);
590,691,766✔
3877
    if (NULL == pCol) {
586,877,841!
3878
      return TSDB_CODE_OUT_OF_RANGE;
×
3879
    }
3880
    if ((nullList[i] = colDataIsNull_s(pCol, rowIndex)) == true) {
1,173,755,682✔
3881
      offset += pCol->info.bytes;
30,213✔
3882
      continue;
30,213✔
3883
    }
3884

3885
    char* p = colDataGetData(pCol, rowIndex);
586,847,628!
3886
    if (IS_VAR_DATA_TYPE(pCol->info.type)) {
586,847,628!
3887
      int32_t bytes = calcStrBytesByType(pCol->info.type, p);
×
3888
      (void)memcpy(pStart + offset, p, bytes);
46,908✔
3889
    } else {
3890
      (void)memcpy(pStart + offset, p, pCol->info.bytes);
587,693,593✔
3891
    }
3892

3893
    offset += pCol->info.bytes;
587,740,501✔
3894
  }
3895

3896
  *res = buf;
587,724,192✔
3897
  return TSDB_CODE_SUCCESS;
587,724,192✔
3898
}
3899

3900
static int32_t doSaveTupleData(SSerializeDataHandle* pHandle, const void* pBuf, size_t length, SWinKey* key,
587,750,556✔
3901
                               STuplePos* pPos, SFunctionStateStore* pStore) {
3902
  STuplePos p = {0};
587,750,556✔
3903
  if (pHandle->pBuf != NULL) {
587,750,556!
3904
    SFilePage* pPage = NULL;
588,127,173✔
3905

3906
    if (pHandle->currentPage == -1) {
588,127,173✔
3907
      pPage = getNewBufPage(pHandle->pBuf, &pHandle->currentPage);
1,932,100✔
3908
      if (pPage == NULL) {
1,932,111✔
3909
        return terrno;
1✔
3910
      }
3911
      pPage->num = sizeof(SFilePage);
1,932,110✔
3912
    } else {
3913
      pPage = getBufPage(pHandle->pBuf, pHandle->currentPage);
586,195,073✔
3914
      if (pPage == NULL) {
586,604,053!
3915
        return terrno;
×
3916
      }
3917
      if (pPage->num + length > getBufPageSize(pHandle->pBuf)) {
586,604,053✔
3918
        // current page is all used, let's prepare a new buffer page
3919
        releaseBufPage(pHandle->pBuf, pPage);
2,732,540✔
3920
        pPage = getNewBufPage(pHandle->pBuf, &pHandle->currentPage);
2,732,537✔
3921
        if (pPage == NULL) {
2,732,537!
3922
          return terrno;
×
3923
        }
3924
        pPage->num = sizeof(SFilePage);
2,732,537✔
3925
      }
3926
    }
3927

3928
    p = (STuplePos){.pageId = pHandle->currentPage, .offset = pPage->num};
588,484,347✔
3929
    (void)memcpy(pPage->data + pPage->num, pBuf, length);
588,484,347✔
3930

3931
    pPage->num += length;
588,484,347✔
3932
    setBufPageDirty(pPage, true);
588,484,347✔
3933
    releaseBufPage(pHandle->pBuf, pPage);
588,429,382✔
3934
  } else {  // other tuple save policy
3935
    if (pStore->streamStateFuncPut(pHandle->pState, key, pBuf, length) >= 0) {
×
3936
      p.streamTupleKey = *key;
×
3937
    }
3938
  }
3939

3940
  *pPos = p;
588,165,483✔
3941
  return TSDB_CODE_SUCCESS;
588,165,483✔
3942
}
3943

3944
int32_t saveTupleData(SqlFunctionCtx* pCtx, int32_t rowIndex, const SSDataBlock* pSrcBlock, STuplePos* pPos) {
481,866,176✔
3945
  int32_t code = prepareBuf(pCtx);
481,866,176✔
3946
  if (TSDB_CODE_SUCCESS != code) {
481,779,089!
3947
    return code;
×
3948
  }
3949

3950
  SWinKey key = {0};
481,779,089✔
3951
  if (pCtx->saveHandle.pBuf == NULL) {
481,779,089!
3952
    SColumnInfoData* pColInfo = taosArrayGet(pSrcBlock->pDataBlock, pCtx->saveHandle.pState->tsIndex);
×
3953
    if (NULL == pColInfo) {
×
3954
      return TSDB_CODE_OUT_OF_RANGE;
×
3955
    }
3956
    if (pColInfo->info.type != TSDB_DATA_TYPE_TIMESTAMP) {
×
3957
      return TSDB_CODE_FUNC_FUNTION_PARA_TYPE;
×
3958
    }
3959
    key.groupId = pSrcBlock->info.id.groupId;
×
3960
    key.ts = *(int64_t*)colDataGetData(pColInfo, rowIndex);
×
3961
    key.numInGroup = pCtx->pExpr->pExpr->_function.bindExprID;
×
3962
  }
3963

3964
  char* buf = NULL;
481,779,089✔
3965
  code = serializeTupleData(pSrcBlock, rowIndex, &pCtx->subsidiaries, pCtx->subsidiaries.buf, &buf);
481,779,089✔
3966
  if (TSDB_CODE_SUCCESS != code) {
480,057,795!
3967
    return code;
×
3968
  }
3969
  return doSaveTupleData(&pCtx->saveHandle, buf, pCtx->subsidiaries.rowLen, &key, pPos, pCtx->pStore);
480,057,795✔
3970
}
3971

3972
static int32_t doUpdateTupleData(SSerializeDataHandle* pHandle, const void* pBuf, size_t length, STuplePos* pPos,
109,106,763✔
3973
                                 SFunctionStateStore* pStore) {
3974
  if (pHandle->pBuf != NULL) {
109,106,763!
3975
    SFilePage* pPage = getBufPage(pHandle->pBuf, pPos->pageId);
109,107,190✔
3976
    if (pPage == NULL) {
109,115,282!
3977
      return terrno;
×
3978
    }
3979
    (void)memcpy(pPage->data + pPos->offset, pBuf, length);
109,115,282✔
3980
    setBufPageDirty(pPage, true);
109,115,282✔
3981
    releaseBufPage(pHandle->pBuf, pPage);
109,112,763✔
3982
  } else {
3983
    int32_t code = pStore->streamStateFuncPut(pHandle->pState, &pPos->streamTupleKey, pBuf, length);
×
3984
    if (TSDB_CODE_SUCCESS != code) {
×
3985
      return code;
×
3986
    }
3987
  }
3988

3989
  return TSDB_CODE_SUCCESS;
109,101,752✔
3990
}
3991

3992
int32_t updateTupleData(SqlFunctionCtx* pCtx, int32_t rowIndex, const SSDataBlock* pSrcBlock, STuplePos* pPos) {
109,132,514✔
3993
  int32_t code = prepareBuf(pCtx);
109,132,514✔
3994
  if (TSDB_CODE_SUCCESS != code) {
109,129,523!
3995
    return code;
×
3996
  }
3997

3998
  char* buf = NULL;
109,129,523✔
3999
  code = serializeTupleData(pSrcBlock, rowIndex, &pCtx->subsidiaries, pCtx->subsidiaries.buf, &buf);
109,129,523✔
4000
  if (TSDB_CODE_SUCCESS != code) {
109,072,570!
4001
    return code;
×
4002
  }
4003
  return doUpdateTupleData(&pCtx->saveHandle, buf, pCtx->subsidiaries.rowLen, pPos, pCtx->pStore);
109,072,570✔
4004
}
4005

4006
static int32_t doLoadTupleData(SSerializeDataHandle* pHandle, const STuplePos* pPos, SFunctionStateStore* pStore,
411,614,876✔
4007
                               char** value) {
4008
  if (pHandle->pBuf != NULL) {
411,614,876!
4009
    SFilePage* pPage = getBufPage(pHandle->pBuf, pPos->pageId);
411,732,309✔
4010
    if (pPage == NULL) {
413,410,627!
4011
      *value = NULL;
×
4012
      return terrno;
×
4013
    }
4014
    *value = pPage->data + pPos->offset;
413,410,627✔
4015
    releaseBufPage(pHandle->pBuf, pPage);
413,410,627✔
4016
    return TSDB_CODE_SUCCESS;
413,226,303✔
4017
  } else {
4018
    *value = NULL;
×
4019
    int32_t vLen;
4020
    int32_t code = pStore->streamStateFuncGet(pHandle->pState, &pPos->streamTupleKey, (void**)(value), &vLen);
×
4021
    if (TSDB_CODE_SUCCESS != code) {
×
4022
      return code;
×
4023
    }
4024
    return TSDB_CODE_SUCCESS;
×
4025
  }
4026
}
4027

4028
int32_t loadTupleData(SqlFunctionCtx* pCtx, const STuplePos* pPos, char** value) {
410,412,137✔
4029
  return doLoadTupleData(&pCtx->saveHandle, pPos, pCtx->pStore, value);
410,412,137✔
4030
}
4031

4032
int32_t topBotFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
101,465,385✔
4033
  int32_t code = TSDB_CODE_SUCCESS;
101,465,385✔
4034

4035
  SResultRowEntryInfo* pEntryInfo = GET_RES_INFO(pCtx);
101,465,385✔
4036
  STopBotRes*          pRes = getTopBotOutputInfo(pCtx);
101,465,385✔
4037

4038
  int16_t type = pCtx->pExpr->base.resSchema.type;
101,464,837✔
4039
  int32_t slotId = pCtx->pExpr->base.resSchema.slotId;
101,464,837✔
4040

4041
  SColumnInfoData* pCol = taosArrayGet(pBlock->pDataBlock, slotId);
101,464,837✔
4042
  if (NULL == pCol) {
101,060,638!
4043
    return TSDB_CODE_OUT_OF_RANGE;
×
4044
  }
4045

4046
  // todo assign the tag value and the corresponding row data
4047
  int32_t currentRow = pBlock->info.rows;
101,060,638✔
4048
  if (pEntryInfo->numOfRes <= 0) {
101,060,638✔
4049
    colDataSetNULL(pCol, currentRow);
426!
4050
    code = setSelectivityValue(pCtx, pBlock, &pRes->nullTuplePos, currentRow);
426✔
4051
    return code;
426✔
4052
  }
4053
  for (int32_t i = 0; i < pEntryInfo->numOfRes; ++i) {
254,729,271✔
4054
    STopBotResItem* pItem = &pRes->pItems[i];
154,112,841✔
4055
    code = colDataSetVal(pCol, currentRow, (const char*)&pItem->v.i, false);
154,112,841✔
4056
    if (TSDB_CODE_SUCCESS != code) {
153,640,259!
4057
      return code;
×
4058
    }
4059
#ifdef BUF_PAGE_DEBUG
4060
    qDebug("page_finalize i:%d,item:%p,pageId:%d, offset:%d\n", i, pItem, pItem->tuplePos.pageId,
4061
           pItem->tuplePos.offset);
4062
#endif
4063
    code = setSelectivityValue(pCtx, pBlock, &pRes->pItems[i].tuplePos, currentRow);
153,640,259✔
4064
    if (TSDB_CODE_SUCCESS != code) {
153,669,059!
4065
      return code;
×
4066
    }
4067
    currentRow += 1;
153,669,059✔
4068
  }
4069

4070
  return code;
100,616,430✔
4071
}
4072

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

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

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

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

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

4146
int32_t getSpreadInfoSize() { return (int32_t)sizeof(SSpreadInfo); }
2,493,702✔
4147

4148
bool getSpreadFuncEnv(SFunctionNode* UNUSED_PARAM(pFunc), SFuncExecEnv* pEnv) {
163,821✔
4149
  pEnv->calcMemSize = sizeof(SSpreadInfo);
163,821✔
4150
  return true;
163,821✔
4151
}
4152

4153
int32_t spreadFunctionSetup(SqlFunctionCtx* pCtx, SResultRowEntryInfo* pResultInfo) {
11,163,099✔
4154
  if (pResultInfo->initialized) {
11,163,099!
4155
    return TSDB_CODE_SUCCESS;
×
4156
  }
4157
  if (TSDB_CODE_SUCCESS != functionSetup(pCtx, pResultInfo)) {
11,163,099!
4158
    return TSDB_CODE_FUNC_SETUP_ERROR;
×
4159
  }
4160

4161
  SSpreadInfo* pInfo = GET_ROWCELL_INTERBUF(pResultInfo);
11,163,104✔
4162
  SET_DOUBLE_VAL(&pInfo->min, DBL_MAX);
11,163,104✔
4163
  SET_DOUBLE_VAL(&pInfo->max, -DBL_MAX);
11,163,104✔
4164
  pInfo->hasResult = false;
11,163,104✔
4165
  return TSDB_CODE_SUCCESS;
11,163,104✔
4166
}
4167

4168
int32_t spreadFunction(SqlFunctionCtx* pCtx) {
10,542,127✔
4169
  int32_t numOfElems = 0;
10,542,127✔
4170

4171
  // Only the pre-computing information loaded and actual data does not loaded
4172
  SInputColumnInfoData* pInput = &pCtx->input;
10,542,127✔
4173
  SColumnDataAgg*       pAgg = pInput->pColumnDataAgg[0];
10,542,127✔
4174
  int32_t               type = pInput->pData[0]->info.type;
10,542,127✔
4175

4176
  SSpreadInfo* pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
10,542,127✔
4177

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

4195
    if (GET_DOUBLE_VAL(&pInfo->min) > tmin) {
×
4196
      SET_DOUBLE_VAL(&pInfo->min, tmin);
×
4197
    }
4198

4199
    if (GET_DOUBLE_VAL(&pInfo->max) < tmax) {
×
4200
      SET_DOUBLE_VAL(&pInfo->max, tmax);
×
4201
    }
4202

4203
  } else {  // computing based on the true data block
4204
    SColumnInfoData* pCol = pInput->pData[0];
10,542,127✔
4205

4206
    int32_t start = pInput->startRowIndex;
10,542,127✔
4207
    // check the valid data one by one
4208
    for (int32_t i = start; i < pInput->numOfRows + start; ++i) {
45,525,957✔
4209
      if (colDataIsNull_f(pCol, i)) {
34,983,876✔
4210
        continue;
776,922✔
4211
      }
4212

4213
      char* data = colDataGetData(pCol, i);
34,206,954!
4214

4215
      double v = 0;
34,206,954✔
4216
      GET_TYPED_DATA(v, double, type, data, typeGetTypeModFromColInfo(&pCol->info));
34,206,954!
4217
      if (v < GET_DOUBLE_VAL(&pInfo->min)) {
34,206,908✔
4218
        SET_DOUBLE_VAL(&pInfo->min, v);
11,549,152✔
4219
      }
4220

4221
      if (v > GET_DOUBLE_VAL(&pInfo->max)) {
34,206,908✔
4222
        SET_DOUBLE_VAL(&pInfo->max, v);
17,873,737✔
4223
      }
4224

4225
      numOfElems += 1;
34,206,908✔
4226
    }
4227
  }
4228

4229
_spread_over:
10,542,081✔
4230
  // data in the check operation are all null, not output
4231
  SET_VAL(GET_RES_INFO(pCtx), numOfElems, 1);
10,542,081✔
4232
  if (numOfElems > 0) {
10,542,081✔
4233
    pInfo->hasResult = true;
10,529,509✔
4234
  }
4235

4236
  return TSDB_CODE_SUCCESS;
10,542,081✔
4237
}
4238

4239
static void spreadTransferInfo(SSpreadInfo* pInput, SSpreadInfo* pOutput) {
2,493,441✔
4240
  pOutput->hasResult = pInput->hasResult;
2,493,441✔
4241
  if (pInput->max > pOutput->max) {
2,493,441✔
4242
    pOutput->max = pInput->max;
2,489,276✔
4243
  }
4244

4245
  if (pInput->min < pOutput->min) {
2,493,441✔
4246
    pOutput->min = pInput->min;
2,489,280✔
4247
  }
4248
}
2,493,441✔
4249

4250
int32_t spreadFunctionMerge(SqlFunctionCtx* pCtx) {
2,489,430✔
4251
  SInputColumnInfoData* pInput = &pCtx->input;
2,489,430✔
4252
  SColumnInfoData*      pCol = pInput->pData[0];
2,489,430✔
4253

4254
  if (IS_NULL_TYPE(pCol->info.type)) {
2,489,430!
4255
    SET_VAL(GET_RES_INFO(pCtx), 0, 1);
×
4256
    return TSDB_CODE_SUCCESS;
×
4257
  }
4258

4259
  if (pCol->info.type != TSDB_DATA_TYPE_BINARY) {
2,489,430!
4260
    return TSDB_CODE_FUNC_FUNTION_PARA_TYPE;
×
4261
  }
4262

4263
  SSpreadInfo* pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
2,489,430✔
4264

4265
  int32_t start = pInput->startRowIndex;
2,489,430✔
4266
  for (int32_t i = start; i < start + pInput->numOfRows; ++i) {
4,982,901✔
4267
    if (colDataIsNull_s(pCol, i)) continue;
4,986,942!
4268
    char*        data = colDataGetData(pCol, i);
2,493,471!
4269
    SSpreadInfo* pInputInfo = (SSpreadInfo*)varDataVal(data);
2,493,471✔
4270
    if (pInputInfo->hasResult) {
2,493,471✔
4271
      spreadTransferInfo(pInputInfo, pInfo);
2,493,441✔
4272
    }
4273
  }
4274

4275
  if (pInfo->hasResult) {
2,489,430✔
4276
    GET_RES_INFO(pCtx)->numOfRes = 1;
2,489,400✔
4277
  }
4278

4279
  return TSDB_CODE_SUCCESS;
2,489,430✔
4280
}
4281

4282
int32_t spreadFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
8,649,825✔
4283
  SSpreadInfo* pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
8,649,825✔
4284
  if (pInfo->hasResult == true) {
8,649,825✔
4285
    SET_DOUBLE_VAL(&pInfo->result, pInfo->max - pInfo->min);
8,637,338✔
4286
  } else {
4287
    GET_RES_INFO(pCtx)->isNullRes = 1;
12,487✔
4288
  }
4289
  return functionFinalize(pCtx, pBlock);
8,649,825✔
4290
}
4291

4292
int32_t spreadPartialFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
2,493,702✔
4293
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
2,493,702✔
4294
  SSpreadInfo*         pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
2,493,702✔
4295
  int32_t              resultBytes = getSpreadInfoSize();
2,493,702✔
4296
  char*                res = taosMemoryCalloc(resultBytes + VARSTR_HEADER_SIZE, sizeof(char));
2,493,701!
4297

4298
  if (NULL == res) {
2,493,705!
4299
    return terrno;
×
4300
  }
4301
  (void)memcpy(varDataVal(res), pInfo, resultBytes);
2,493,705✔
4302
  varDataSetLen(res, resultBytes);
2,493,705✔
4303

4304
  int32_t          slotId = pCtx->pExpr->base.resSchema.slotId;
2,493,705✔
4305
  int32_t          code = TSDB_CODE_SUCCESS;
2,493,705✔
4306
  SColumnInfoData* pCol = taosArrayGet(pBlock->pDataBlock, slotId);
2,493,705✔
4307
  if (NULL == pCol) {
2,493,702!
4308
    code = terrno;
×
4309
    goto _exit;
×
4310
  }
4311

4312
  code = colDataSetVal(pCol, pBlock->info.rows, res, false);
2,493,702✔
4313
  if (TSDB_CODE_SUCCESS != code) {
2,493,709!
4314
    goto _exit;
×
4315
  }
4316

4317
_exit:
2,493,709✔
4318
  taosMemoryFree(res);
2,493,709!
4319
  return code;
2,493,708✔
4320
}
4321

4322
int32_t spreadCombine(SqlFunctionCtx* pDestCtx, SqlFunctionCtx* pSourceCtx) {
×
4323
  SResultRowEntryInfo* pDResInfo = GET_RES_INFO(pDestCtx);
×
4324
  SSpreadInfo*         pDBuf = GET_ROWCELL_INTERBUF(pDResInfo);
×
4325

4326
  SResultRowEntryInfo* pSResInfo = GET_RES_INFO(pSourceCtx);
×
4327
  SSpreadInfo*         pSBuf = GET_ROWCELL_INTERBUF(pSResInfo);
×
4328
  spreadTransferInfo(pSBuf, pDBuf);
×
4329
  pDResInfo->numOfRes = TMAX(pDResInfo->numOfRes, pSResInfo->numOfRes);
×
4330
  pDResInfo->isNullRes &= pSResInfo->isNullRes;
×
4331
  return TSDB_CODE_SUCCESS;
×
4332
}
4333

4334
int32_t getElapsedInfoSize() { return (int32_t)sizeof(SElapsedInfo); }
×
4335

4336
bool getElapsedFuncEnv(SFunctionNode* UNUSED_PARAM(pFunc), SFuncExecEnv* pEnv) {
268,024✔
4337
  pEnv->calcMemSize = sizeof(SElapsedInfo);
268,024✔
4338
  return true;
268,024✔
4339
}
4340

4341
int32_t elapsedFunctionSetup(SqlFunctionCtx* pCtx, SResultRowEntryInfo* pResultInfo) {
24,407,019✔
4342
  if (pResultInfo->initialized) {
24,407,019!
4343
    return TSDB_CODE_SUCCESS;
×
4344
  }
4345
  if (TSDB_CODE_SUCCESS != functionSetup(pCtx, pResultInfo)) {
24,407,019!
4346
    return TSDB_CODE_FUNC_SETUP_ERROR;
×
4347
  }
4348

4349
  SElapsedInfo* pInfo = GET_ROWCELL_INTERBUF(pResultInfo);
24,407,018✔
4350
  pInfo->result = 0;
24,407,018✔
4351
  pInfo->min = TSKEY_MAX;
24,407,018✔
4352
  pInfo->max = 0;
24,407,018✔
4353

4354
  if (pCtx->numOfParams > 1) {
24,407,018✔
4355
    pInfo->timeUnit = pCtx->param[1].param.i;
8,255,392✔
4356
  } else {
4357
    pInfo->timeUnit = 1;
16,151,626✔
4358
  }
4359

4360
  return TSDB_CODE_SUCCESS;
24,407,018✔
4361
}
4362

4363
int32_t elapsedFunction(SqlFunctionCtx* pCtx) {
24,450,379✔
4364
  int32_t numOfElems = 0;
24,450,379✔
4365

4366
  // Only the pre-computing information loaded and actual data does not loaded
4367
  SInputColumnInfoData* pInput = &pCtx->input;
24,450,379✔
4368
  SColumnDataAgg*       pAgg = pInput->pColumnDataAgg[0];
24,450,379✔
4369

4370
  SElapsedInfo* pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
24,450,379✔
4371

4372
  numOfElems = pInput->numOfRows;  // since this is the primary timestamp, no need to exclude NULL values
24,450,379✔
4373
  if (numOfElems == 0) {
24,450,379✔
4374
    // for stream
4375
    if (pCtx->end.key != INT64_MIN) {
3,564!
4376
      pInfo->max = pCtx->end.key + 1;
×
4377
    }
4378
    goto _elapsed_over;
3,564✔
4379
  }
4380

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

4406
    SColumnInfoData* pCol = pInput->pData[0];
24,446,815✔
4407

4408
    int32_t start = pInput->startRowIndex;
24,446,815✔
4409
    TSKEY*  ptsList = (int64_t*)colDataGetData(pCol, 0);
24,446,815!
4410
    if (pCtx->order == TSDB_ORDER_DESC) {
24,446,815✔
4411
      if (pCtx->start.key == INT64_MIN) {
1,740!
4412
        pInfo->max = (pInfo->max < ptsList[start]) ? ptsList[start] : pInfo->max;
1,740✔
4413
      } else {
4414
        pInfo->max = pCtx->start.key + 1;
×
4415
      }
4416

4417
      if (pCtx->end.key == INT64_MIN) {
1,740!
4418
        pInfo->min =
1,740✔
4419
            (pInfo->min > ptsList[start + pInput->numOfRows - 1]) ? ptsList[start + pInput->numOfRows - 1] : pInfo->min;
1,740✔
4420
      } else {
4421
        pInfo->min = pCtx->end.key;
×
4422
      }
4423
    } else {
4424
      if (pCtx->start.key == INT64_MIN) {
24,445,075✔
4425
        pInfo->min = (pInfo->min > ptsList[start]) ? ptsList[start] : pInfo->min;
12,122,088✔
4426
      } else {
4427
        pInfo->min = pCtx->start.key;
12,322,987✔
4428
      }
4429

4430
      if (pCtx->end.key == INT64_MIN) {
24,445,075✔
4431
        pInfo->max =
11,456,202✔
4432
            (pInfo->max < ptsList[start + pInput->numOfRows - 1]) ? ptsList[start + pInput->numOfRows - 1] : pInfo->max;
11,456,202✔
4433
      } else {
4434
        pInfo->max = pCtx->end.key + 1;
12,988,873✔
4435
      }
4436
    }
4437
  }
4438

4439
_elapsed_over:
24,450,379✔
4440
  // data in the check operation are all null, not output
4441
  SET_VAL(GET_RES_INFO(pCtx), numOfElems, 1);
24,450,379✔
4442

4443
  return TSDB_CODE_SUCCESS;
24,450,379✔
4444
}
4445

4446
static void elapsedTransferInfo(SElapsedInfo* pInput, SElapsedInfo* pOutput) {
×
4447
  pOutput->timeUnit = pInput->timeUnit;
×
4448
  if (pOutput->min > pInput->min) {
×
4449
    pOutput->min = pInput->min;
×
4450
  }
4451

4452
  if (pOutput->max < pInput->max) {
×
4453
    pOutput->max = pInput->max;
×
4454
  }
4455
}
×
4456

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

4464
  SElapsedInfo* pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
×
4465

4466
  int32_t start = pInput->startRowIndex;
×
4467

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

4474
  SET_VAL(GET_RES_INFO(pCtx), 1, 1);
×
4475
  return TSDB_CODE_SUCCESS;
×
4476
}
4477

4478
int32_t elapsedFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
24,386,859✔
4479
  SElapsedInfo* pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
24,386,859✔
4480
  double        result = (double)pInfo->max - (double)pInfo->min;
24,386,859✔
4481
  result = (result >= 0) ? result : -result;
24,386,859✔
4482
  pInfo->result = result / pInfo->timeUnit;
24,386,859✔
4483
  return functionFinalize(pCtx, pBlock);
24,386,859✔
4484
}
4485

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

4492
  if (NULL == res) {
×
4493
    return terrno;
×
4494
  }
4495
  (void)memcpy(varDataVal(res), pInfo, resultBytes);
×
4496
  varDataSetLen(res, resultBytes);
×
4497

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

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

4515
int32_t elapsedCombine(SqlFunctionCtx* pDestCtx, SqlFunctionCtx* pSourceCtx) {
×
4516
  SResultRowEntryInfo* pDResInfo = GET_RES_INFO(pDestCtx);
×
4517
  SElapsedInfo*        pDBuf = GET_ROWCELL_INTERBUF(pDResInfo);
×
4518

4519
  SResultRowEntryInfo* pSResInfo = GET_RES_INFO(pSourceCtx);
×
4520
  SElapsedInfo*        pSBuf = GET_ROWCELL_INTERBUF(pSResInfo);
×
4521

4522
  elapsedTransferInfo(pSBuf, pDBuf);
×
4523
  pDResInfo->numOfRes = TMAX(pDResInfo->numOfRes, pSResInfo->numOfRes);
×
4524
  pDResInfo->isNullRes &= pSResInfo->isNullRes;
×
4525
  return TSDB_CODE_SUCCESS;
×
4526
}
4527

4528
int32_t getHistogramInfoSize() {
7,167,029✔
4529
  return (int32_t)sizeof(SHistoFuncInfo) + HISTOGRAM_MAX_BINS_NUM * sizeof(SHistoFuncBin);
7,167,029✔
4530
}
4531

4532
bool getHistogramFuncEnv(SFunctionNode* UNUSED_PARAM(pFunc), SFuncExecEnv* pEnv) {
311,896✔
4533
  pEnv->calcMemSize = sizeof(SHistoFuncInfo) + HISTOGRAM_MAX_BINS_NUM * sizeof(SHistoFuncBin);
311,896✔
4534
  return true;
311,896✔
4535
}
4536

4537
static int8_t getHistogramBinType(char* binTypeStr) {
36,411,252✔
4538
  int8_t binType;
4539
  if (strcasecmp(binTypeStr, "user_input") == 0) {
36,411,252✔
4540
    binType = USER_INPUT_BIN;
2,893✔
4541
  } else if (strcasecmp(binTypeStr, "linear_bin") == 0) {
36,408,359✔
4542
    binType = LINEAR_BIN;
3,278✔
4543
  } else if (strcasecmp(binTypeStr, "log_bin") == 0) {
36,405,081!
4544
    binType = LOG_BIN;
36,406,686✔
4545
  } else {
4546
    binType = UNKNOWN_BIN;
×
4547
  }
4548

4549
  return binType;
36,411,252✔
4550
}
4551

4552
static int32_t getHistogramBinDesc(SHistoFuncInfo* pInfo, char* binDescStr, int8_t binType, bool normalized) {
36,411,015✔
4553
  cJSON*  binDesc = cJSON_Parse(binDescStr);
36,411,015✔
4554
  int32_t numOfBins;
4555
  double* intervals;
4556
  if (cJSON_IsObject(binDesc)) { /* linaer/log bins */
36,414,312✔
4557
    int32_t numOfParams = cJSON_GetArraySize(binDesc);
36,411,550✔
4558
    int32_t startIndex;
4559
    if (numOfParams != 4) {
36,411,105!
4560
      cJSON_Delete(binDesc);
×
4561
      return TSDB_CODE_FAILED;
×
4562
    }
4563

4564
    cJSON* start = cJSON_GetObjectItem(binDesc, "start");
36,411,105✔
4565
    cJSON* factor = cJSON_GetObjectItem(binDesc, "factor");
36,410,639✔
4566
    cJSON* width = cJSON_GetObjectItem(binDesc, "width");
36,411,165✔
4567
    cJSON* count = cJSON_GetObjectItem(binDesc, "count");
36,410,824✔
4568
    cJSON* infinity = cJSON_GetObjectItem(binDesc, "infinity");
36,411,264✔
4569

4570
    if (!cJSON_IsNumber(start) || !cJSON_IsNumber(count) || !cJSON_IsBool(infinity)) {
36,411,314!
4571
      cJSON_Delete(binDesc);
×
4572
      return TSDB_CODE_FAILED;
×
4573
    }
4574

4575
    if (count->valueint <= 0 || count->valueint > 1000) {  // limit count to 1000
36,410,903!
4576
      cJSON_Delete(binDesc);
190✔
4577
      return TSDB_CODE_FAILED;
×
4578
    }
4579

4580
    if (isinf(start->valuedouble) || (width != NULL && isinf(width->valuedouble)) ||
36,410,713!
4581
        (factor != NULL && isinf(factor->valuedouble)) || (count != NULL && isinf(count->valuedouble))) {
36,410,713!
4582
      cJSON_Delete(binDesc);
×
4583
      return TSDB_CODE_FAILED;
×
4584
    }
4585

4586
    int32_t counter = (int32_t)count->valueint;
36,410,713✔
4587
    if (infinity->valueint == false) {
36,410,713✔
4588
      startIndex = 0;
23,459,393✔
4589
      numOfBins = counter + 1;
23,459,393✔
4590
    } else {
4591
      startIndex = 1;
12,951,320✔
4592
      numOfBins = counter + 3;
12,951,320✔
4593
    }
4594

4595
    intervals = taosMemoryCalloc(numOfBins, sizeof(double));
36,410,713!
4596
    if (NULL == intervals) {
36,409,505!
4597
      cJSON_Delete(binDesc);
×
4598
      qError("histogram function out of memory");
×
4599
      return terrno;
×
4600
    }
4601
    if (cJSON_IsNumber(width) && factor == NULL && binType == LINEAR_BIN) {
36,409,505✔
4602
      // linear bin process
4603
      if (width->valuedouble == 0) {
3,275!
4604
        taosMemoryFree(intervals);
×
4605
        cJSON_Delete(binDesc);
×
4606
        return TSDB_CODE_FAILED;
×
4607
      }
4608
      for (int i = 0; i < counter + 1; ++i) {
31,664✔
4609
        intervals[startIndex] = start->valuedouble + i * width->valuedouble;
28,389✔
4610
        if (isinf(intervals[startIndex])) {
28,389!
4611
          taosMemoryFree(intervals);
×
4612
          cJSON_Delete(binDesc);
×
4613
          return TSDB_CODE_FAILED;
×
4614
        }
4615
        startIndex++;
28,389✔
4616
      }
4617
    } else if (cJSON_IsNumber(factor) && width == NULL && binType == LOG_BIN) {
36,406,087!
4618
      // log bin process
4619
      if (start->valuedouble == 0) {
36,405,683!
4620
        taosMemoryFree(intervals);
×
4621
        cJSON_Delete(binDesc);
×
4622
        return TSDB_CODE_FAILED;
×
4623
      }
4624
      if (factor->valuedouble < 0 || factor->valuedouble == 0 || factor->valuedouble == 1) {
36,405,683!
4625
        taosMemoryFree(intervals);
56!
4626
        cJSON_Delete(binDesc);
×
4627
        return TSDB_CODE_FAILED;
×
4628
      }
4629
      for (int i = 0; i < counter + 1; ++i) {
254,806,915✔
4630
        intervals[startIndex] = start->valuedouble * pow(factor->valuedouble, i * 1.0);
218,401,288✔
4631
        if (isinf(intervals[startIndex])) {
218,401,288!
4632
          taosMemoryFree(intervals);
×
4633
          cJSON_Delete(binDesc);
×
4634
          return TSDB_CODE_FAILED;
×
4635
        }
4636
        startIndex++;
218,401,288✔
4637
      }
4638
    } else {
4639
      taosMemoryFree(intervals);
108!
4640
      cJSON_Delete(binDesc);
×
4641
      return TSDB_CODE_FAILED;
×
4642
    }
4643

4644
    if (infinity->valueint == true) {
36,408,902✔
4645
      intervals[0] = -INFINITY;
12,952,126✔
4646
      intervals[numOfBins - 1] = INFINITY;
12,952,126✔
4647
      // in case of desc bin orders, -inf/inf should be swapped
4648
      if (numOfBins < 4) {
12,952,126!
4649
        return TSDB_CODE_FAILED;
×
4650
      }
4651
      if (intervals[1] > intervals[numOfBins - 2]) {
12,952,126✔
4652
        TSWAP(intervals[0], intervals[numOfBins - 1]);
12,950,268✔
4653
      }
4654
    }
4655
  } else if (cJSON_IsArray(binDesc)) { /* user input bins */
2,890!
4656
    if (binType != USER_INPUT_BIN) {
2,891!
4657
      cJSON_Delete(binDesc);
×
4658
      return TSDB_CODE_FAILED;
×
4659
    }
4660
    numOfBins = cJSON_GetArraySize(binDesc);
2,891✔
4661
    intervals = taosMemoryCalloc(numOfBins, sizeof(double));
2,893!
4662
    if (NULL == intervals) {
2,891!
4663
      cJSON_Delete(binDesc);
×
4664
      qError("histogram function out of memory");
×
4665
      return terrno;
×
4666
    }
4667
    cJSON* bin = binDesc->child;
2,891✔
4668
    if (bin == NULL) {
2,891!
4669
      taosMemoryFree(intervals);
×
4670
      cJSON_Delete(binDesc);
×
4671
      return TSDB_CODE_FAILED;
×
4672
    }
4673
    int i = 0;
2,891✔
4674
    while (bin) {
12,506✔
4675
      intervals[i] = bin->valuedouble;
9,614✔
4676
      if (!cJSON_IsNumber(bin)) {
9,614✔
4677
        taosMemoryFree(intervals);
1!
4678
        cJSON_Delete(binDesc);
×
4679
        return TSDB_CODE_FAILED;
×
4680
      }
4681
      if (i != 0 && intervals[i] <= intervals[i - 1]) {
9,615!
4682
        taosMemoryFree(intervals);
×
4683
        cJSON_Delete(binDesc);
×
4684
        return TSDB_CODE_FAILED;
×
4685
      }
4686
      bin = bin->next;
9,615✔
4687
      i++;
9,615✔
4688
    }
4689
  } else {
4690
    cJSON_Delete(binDesc);
×
4691
    return TSDB_CODE_FAILED;
×
4692
  }
4693

4694
  pInfo->numOfBins = numOfBins - 1;
36,411,794✔
4695
  pInfo->normalized = normalized;
36,411,794✔
4696
  for (int32_t i = 0; i < pInfo->numOfBins; ++i) {
244,360,767✔
4697
    pInfo->bins[i].lower = intervals[i] < intervals[i + 1] ? intervals[i] : intervals[i + 1];
207,948,973✔
4698
    pInfo->bins[i].upper = intervals[i + 1] > intervals[i] ? intervals[i + 1] : intervals[i];
207,948,973✔
4699
    pInfo->bins[i].count = 0;
207,948,973✔
4700
  }
4701

4702
  taosMemoryFree(intervals);
36,411,794!
4703
  cJSON_Delete(binDesc);
36,412,009✔
4704

4705
  return TSDB_CODE_SUCCESS;
36,414,164✔
4706
}
4707

4708
int32_t histogramFunctionSetup(SqlFunctionCtx* pCtx, SResultRowEntryInfo* pResultInfo) {
36,410,877✔
4709
  if (pResultInfo->initialized) {
36,410,877!
4710
    return TSDB_CODE_SUCCESS;
×
4711
  }
4712
  if (TSDB_CODE_SUCCESS != functionSetup(pCtx, pResultInfo)) {
36,410,877!
4713
    return TSDB_CODE_FUNC_SETUP_ERROR;
×
4714
  }
4715

4716
  SHistoFuncInfo* pInfo = GET_ROWCELL_INTERBUF(pResultInfo);
36,412,516✔
4717
  pInfo->numOfBins = 0;
36,412,516✔
4718
  pInfo->totalCount = 0;
36,412,516✔
4719
  pInfo->normalized = 0;
36,412,516✔
4720

4721
  char* binTypeStr = taosStrndup(varDataVal(pCtx->param[1].param.pz), varDataLen(pCtx->param[1].param.pz));
36,412,516!
4722
  if (binTypeStr == NULL) {
36,411,440!
4723
    return terrno;
×
4724
  }
4725
  int8_t binType = getHistogramBinType(binTypeStr);
36,411,440✔
4726
  taosMemoryFree(binTypeStr);
36,412,070!
4727

4728
  if (binType == UNKNOWN_BIN) {
36,410,173!
4729
    return TSDB_CODE_FUNC_FUNTION_PARA_VALUE;
×
4730
  }
4731
  char* binDesc = taosStrndup(varDataVal(pCtx->param[2].param.pz), varDataLen(pCtx->param[2].param.pz));
36,410,173!
4732
  if (binDesc == NULL) {
36,411,213!
4733
    return terrno;
×
4734
  }
4735
  int64_t normalized = pCtx->param[3].param.i;
36,411,213✔
4736
  if (normalized != 0 && normalized != 1) {
36,411,213!
4737
    taosMemoryFree(binDesc);
×
4738
    return TSDB_CODE_FUNC_FUNTION_PARA_VALUE;
×
4739
  }
4740
  int32_t code = getHistogramBinDesc(pInfo, binDesc, binType, (bool)normalized);
36,411,213✔
4741
  if (TSDB_CODE_SUCCESS != code) {
36,413,887!
4742
    taosMemoryFree(binDesc);
×
4743
    return code;
×
4744
  }
4745
  taosMemoryFree(binDesc);
36,413,887!
4746

4747
  return TSDB_CODE_SUCCESS;
36,411,558✔
4748
}
4749

4750
static int32_t histogramFunctionImpl(SqlFunctionCtx* pCtx, bool isPartial) {
40,993,567✔
4751
  SHistoFuncInfo* pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
40,993,567✔
4752

4753
  SInputColumnInfoData* pInput = &pCtx->input;
40,993,567✔
4754
  SColumnInfoData*      pCol = pInput->pData[0];
40,993,567✔
4755

4756
  int32_t type = pInput->pData[0]->info.type;
40,993,567✔
4757

4758
  int32_t start = pInput->startRowIndex;
40,993,567✔
4759
  int32_t numOfRows = pInput->numOfRows;
40,993,567✔
4760

4761
  int32_t numOfElems = 0;
40,993,567✔
4762
  for (int32_t i = start; i < numOfRows + start; ++i) {
143,046,396✔
4763
    if (pCol->hasNull && colDataIsNull_f(pCol, i)) {
102,053,352!
4764
      continue;
379,925✔
4765
    }
4766

4767
    numOfElems++;
101,673,427✔
4768

4769
    char*  data = colDataGetData(pCol, i);
101,673,427!
4770
    double v;
4771
    GET_TYPED_DATA(v, double, type, data, typeGetTypeModFromColInfo(&pCol->info));
101,673,427!
4772

4773
    for (int32_t k = 0; k < pInfo->numOfBins; ++k) {
421,681,185✔
4774
      if (v > pInfo->bins[k].lower && v <= pInfo->bins[k].upper) {
367,776,957✔
4775
        pInfo->bins[k].count++;
47,768,676✔
4776
        pInfo->totalCount++;
47,768,676✔
4777
        break;
47,768,676✔
4778
      }
4779
    }
4780
  }
4781

4782
  if (!isPartial) {
40,993,044✔
4783
    GET_RES_INFO(pCtx)->numOfRes = pInfo->numOfBins;
29,307,186✔
4784
  } else {
4785
    GET_RES_INFO(pCtx)->numOfRes = 1;
11,685,858✔
4786
  }
4787
  return TSDB_CODE_SUCCESS;
40,993,044✔
4788
}
4789

4790
int32_t histogramFunction(SqlFunctionCtx* pCtx) { return histogramFunctionImpl(pCtx, false); }
29,306,402✔
4791

4792
int32_t histogramFunctionPartial(SqlFunctionCtx* pCtx) { return histogramFunctionImpl(pCtx, true); }
11,688,974✔
4793

4794
static void histogramTransferInfo(SHistoFuncInfo* pInput, SHistoFuncInfo* pOutput) {
7,049,461✔
4795
  pOutput->normalized = pInput->normalized;
7,049,461✔
4796
  pOutput->numOfBins = pInput->numOfBins;
7,049,461✔
4797
  pOutput->totalCount += pInput->totalCount;
7,049,461✔
4798
  for (int32_t k = 0; k < pOutput->numOfBins; ++k) {
45,949,969✔
4799
    pOutput->bins[k].lower = pInput->bins[k].lower;
38,900,508✔
4800
    pOutput->bins[k].upper = pInput->bins[k].upper;
38,900,508✔
4801
    pOutput->bins[k].count += pInput->bins[k].count;
38,900,508✔
4802
  }
4803
}
7,049,461✔
4804

4805
int32_t histogramFunctionMerge(SqlFunctionCtx* pCtx) {
7,049,461✔
4806
  SInputColumnInfoData* pInput = &pCtx->input;
7,049,461✔
4807
  SColumnInfoData*      pCol = pInput->pData[0];
7,049,461✔
4808
  if (pCol->info.type != TSDB_DATA_TYPE_BINARY) {
7,049,461!
4809
    return TSDB_CODE_FUNC_FUNTION_PARA_TYPE;
×
4810
  }
4811

4812
  SHistoFuncInfo* pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
7,049,461✔
4813

4814
  int32_t start = pInput->startRowIndex;
7,049,461✔
4815

4816
  for (int32_t i = start; i < start + pInput->numOfRows; ++i) {
14,098,922✔
4817
    char*           data = colDataGetData(pCol, i);
7,049,461!
4818
    SHistoFuncInfo* pInputInfo = (SHistoFuncInfo*)varDataVal(data);
7,049,461✔
4819
    histogramTransferInfo(pInputInfo, pInfo);
7,049,461✔
4820
  }
4821

4822
  SET_VAL(GET_RES_INFO(pCtx), pInfo->numOfBins, pInfo->numOfBins);
7,049,461!
4823
  return TSDB_CODE_SUCCESS;
7,049,461✔
4824
}
4825

4826
int32_t histogramFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
36,098,424✔
4827
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
36,098,424✔
4828
  SHistoFuncInfo*      pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
36,098,424✔
4829
  int32_t              slotId = pCtx->pExpr->base.resSchema.slotId;
36,098,424✔
4830
  SColumnInfoData*     pCol = taosArrayGet(pBlock->pDataBlock, slotId);
36,098,424✔
4831
  int32_t              code = TSDB_CODE_SUCCESS;
36,080,996✔
4832

4833
  int32_t currentRow = pBlock->info.rows;
36,080,996✔
4834
  if (NULL == pCol) {
36,080,996!
4835
    return TSDB_CODE_OUT_OF_RANGE;
×
4836
  }
4837

4838
  if (pInfo->normalized) {
36,080,996✔
4839
    for (int32_t k = 0; k < pResInfo->numOfRes; ++k) {
139,306,816✔
4840
      if (pInfo->totalCount != 0) {
116,093,087✔
4841
        pInfo->bins[k].percentage = pInfo->bins[k].count / (double)pInfo->totalCount;
21,221,624✔
4842
      } else {
4843
        pInfo->bins[k].percentage = 0;
94,871,463✔
4844
      }
4845
    }
4846
  }
4847

4848
  for (int32_t i = 0; i < pResInfo->numOfRes; ++i) {
241,416,962✔
4849
    int32_t len;
4850
    char    buf[512] = {0};
206,249,368✔
4851
    if (!pInfo->normalized) {
206,249,368✔
4852
      len = tsnprintf(varDataVal(buf), sizeof(buf) - VARSTR_HEADER_SIZE,
90,131,391✔
4853
                      "{\"lower_bin\":%g, \"upper_bin\":%g, \"count\":%" PRId64 "}", pInfo->bins[i].lower,
4854
                      pInfo->bins[i].upper, pInfo->bins[i].count);
4855
    } else {
4856
      len = tsnprintf(varDataVal(buf), sizeof(buf) - VARSTR_HEADER_SIZE,
116,117,977✔
4857
                      "{\"lower_bin\":%g, \"upper_bin\":%g, \"count\":%lf}", pInfo->bins[i].lower, pInfo->bins[i].upper,
4858
                      pInfo->bins[i].percentage);
4859
    }
4860
    varDataSetLen(buf, len);
206,255,811✔
4861
    code = colDataSetVal(pCol, currentRow, buf, false);
206,255,811✔
4862
    if (TSDB_CODE_SUCCESS != code) {
205,335,966!
4863
      return code;
×
4864
    }
4865
    currentRow++;
205,335,966✔
4866
  }
4867

4868
  return code;
35,167,594✔
4869
}
4870

4871
int32_t histogramPartialFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
7,167,029✔
4872
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
7,167,029✔
4873
  SHistoFuncInfo*      pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
7,167,029✔
4874
  int32_t              resultBytes = getHistogramInfoSize();
7,167,029✔
4875
  char*                res = taosMemoryCalloc(resultBytes + VARSTR_HEADER_SIZE, sizeof(char));
7,167,029!
4876

4877
  if (NULL == res) {
7,167,032!
4878
    return terrno;
×
4879
  }
4880
  (void)memcpy(varDataVal(res), pInfo, resultBytes);
7,167,032✔
4881
  varDataSetLen(res, resultBytes);
7,167,032✔
4882

4883
  int32_t          slotId = pCtx->pExpr->base.resSchema.slotId;
7,167,032✔
4884
  int32_t          code = TSDB_CODE_SUCCESS;
7,167,032✔
4885
  SColumnInfoData* pCol = taosArrayGet(pBlock->pDataBlock, slotId);
7,167,032✔
4886
  if (NULL == pCol) {
7,167,034!
4887
    code = terrno;
×
4888
    goto _exit;
×
4889
  }
4890
  code = colDataSetVal(pCol, pBlock->info.rows, res, false);
7,167,034✔
4891

4892
_exit:
7,167,031✔
4893
  taosMemoryFree(res);
7,167,031!
4894
  return code;
7,167,034✔
4895
}
4896

4897
int32_t histogramCombine(SqlFunctionCtx* pDestCtx, SqlFunctionCtx* pSourceCtx) {
×
4898
  SResultRowEntryInfo* pDResInfo = GET_RES_INFO(pDestCtx);
×
4899
  SHistoFuncInfo*      pDBuf = GET_ROWCELL_INTERBUF(pDResInfo);
×
4900

4901
  SResultRowEntryInfo* pSResInfo = GET_RES_INFO(pSourceCtx);
×
4902
  SHistoFuncInfo*      pSBuf = GET_ROWCELL_INTERBUF(pSResInfo);
×
4903

4904
  histogramTransferInfo(pSBuf, pDBuf);
×
4905
  pDResInfo->numOfRes = TMAX(pDResInfo->numOfRes, pSResInfo->numOfRes);
×
4906
  pDResInfo->isNullRes &= pSResInfo->isNullRes;
×
4907
  return TSDB_CODE_SUCCESS;
×
4908
}
4909

4910
int32_t getHLLInfoSize() { return (int32_t)sizeof(SHLLInfo); }
3,166✔
4911

4912
bool getHLLFuncEnv(SFunctionNode* UNUSED_PARAM(pFunc), SFuncExecEnv* pEnv) {
42,705✔
4913
  pEnv->calcMemSize = sizeof(SHLLInfo);
42,705✔
4914
  return true;
42,705✔
4915
}
4916

4917
static uint8_t hllCountNum(void* data, int32_t bytes, int32_t* buk) {
3,403,298✔
4918
  uint64_t hash = MurmurHash3_64(data, bytes);
3,403,298✔
4919
  int32_t  index = hash & HLL_BUCKET_MASK;
3,402,641✔
4920
  hash >>= HLL_BUCKET_BITS;
3,402,641✔
4921
  hash |= ((uint64_t)1 << HLL_DATA_BITS);
3,402,641✔
4922
  uint64_t bit = 1;
3,402,641✔
4923
  uint8_t  count = 1;
3,402,641✔
4924
  while ((hash & bit) == 0) {
5,786,151✔
4925
    count++;
2,383,510✔
4926
    bit <<= 1;
2,383,510✔
4927
  }
4928
  *buk = index;
3,402,641✔
4929
  return count;
3,402,641✔
4930
}
4931

4932
static void hllBucketHisto(uint8_t* buckets, int32_t* bucketHisto) {
110,782✔
4933
  uint64_t* word = (uint64_t*)buckets;
110,782✔
4934
  uint8_t*  bytes;
4935

4936
  for (int32_t j = 0; j < HLL_BUCKETS >> 3; j++) {
220,378,570✔
4937
    if (*word == 0) {
220,267,788✔
4938
      bucketHisto[0] += 8;
219,751,467✔
4939
    } else {
4940
      bytes = (uint8_t*)word;
516,321✔
4941
      bucketHisto[bytes[0]]++;
516,321✔
4942
      bucketHisto[bytes[1]]++;
516,321✔
4943
      bucketHisto[bytes[2]]++;
516,321✔
4944
      bucketHisto[bytes[3]]++;
516,321✔
4945
      bucketHisto[bytes[4]]++;
516,321✔
4946
      bucketHisto[bytes[5]]++;
516,321✔
4947
      bucketHisto[bytes[6]]++;
516,321✔
4948
      bucketHisto[bytes[7]]++;
516,321✔
4949
    }
4950
    word++;
220,267,788✔
4951
  }
4952
}
110,782✔
4953
static double hllTau(double x) {
110,772✔
4954
  if (x == 0. || x == 1.) return 0.;
110,772!
4955
  double zPrime;
4956
  double y = 1.0;
×
4957
  double z = 1 - x;
×
4958
  do {
4959
    x = sqrt(x);
×
4960
    zPrime = z;
×
4961
    y *= 0.5;
×
4962
    z -= pow(1 - x, 2) * y;
×
4963
  } while (zPrime != z);
×
4964
  return z / 3;
×
4965
}
4966

4967
static double hllSigma(double x) {
110,781✔
4968
  if (x == 1.0) return INFINITY;
110,781✔
4969
  double zPrime;
4970
  double y = 1;
102,771✔
4971
  double z = x;
102,771✔
4972
  do {
4973
    x *= x;
2,008,834✔
4974
    zPrime = z;
2,008,834✔
4975
    z += x * y;
2,008,834✔
4976
    y += y;
2,008,834✔
4977
  } while (zPrime != z);
2,008,834✔
4978
  return z;
102,771✔
4979
}
4980

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

4988
  double z = m * hllTau((m - buckethisto[HLL_DATA_BITS + 1]) / (double)m);
110,774✔
4989
  for (int j = HLL_DATA_BITS; j >= 1; --j) {
5,646,867✔
4990
    z += buckethisto[j];
5,536,086✔
4991
    z *= 0.5;
5,536,086✔
4992
  }
4993

4994
  z += m * hllSigma(buckethisto[0] / (double)m);
110,781✔
4995
  double E = (double)llroundl(HLL_ALPHA_INF * m * m / z);
110,786✔
4996

4997
  return (uint64_t)E;
110,786✔
4998
}
4999

5000
int32_t hllFunction(SqlFunctionCtx* pCtx) {
117,985✔
5001
  SHLLInfo* pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
117,985✔
5002

5003
  SInputColumnInfoData* pInput = &pCtx->input;
117,985✔
5004
  SColumnInfoData*      pCol = pInput->pData[0];
117,985✔
5005

5006
  int32_t type = pCol->info.type;
117,985✔
5007
  int32_t bytes = pCol->info.bytes;
117,985✔
5008

5009
  int32_t start = pInput->startRowIndex;
117,985✔
5010
  int32_t numOfRows = pInput->numOfRows;
117,985✔
5011

5012
  int32_t numOfElems = 0;
117,985✔
5013
  if (IS_NULL_TYPE(type)) {
117,985✔
5014
    goto _hll_over;
1,242✔
5015
  }
5016

5017
  for (int32_t i = start; i < numOfRows + start; ++i) {
4,230,754✔
5018
    if (pCol->hasNull && colDataIsNull_s(pCol, i)) {
5,336,497!
5019
      continue;
710,913✔
5020
    }
5021

5022
    numOfElems++;
3,403,371✔
5023

5024
    char* data = colDataGetData(pCol, i);
3,403,371!
5025
    if (IS_VAR_DATA_TYPE(type)) {
3,403,371!
5026
      if (IS_STR_DATA_BLOB(type)) {
856,296!
5027
        bytes = blobDataLen(data);
×
5028
        data = blobDataVal(data);
×
5029
      } else {
5030
        bytes = varDataLen(data);
856,296✔
5031
        data = varDataVal(data);
856,296✔
5032
      }
5033
    }
5034

5035
    int32_t index = 0;
3,403,371✔
5036
    uint8_t count = hllCountNum(data, bytes, &index);
3,403,371✔
5037
    uint8_t oldcount = pInfo->buckets[index];
3,403,098✔
5038
    if (count > oldcount) {
3,403,098✔
5039
      pInfo->buckets[index] = count;
549,974✔
5040
    }
5041
  }
5042

5043
_hll_over:
116,470✔
5044
  pInfo->totalCount += numOfElems;
117,712✔
5045

5046
  if (pInfo->totalCount == 0 && !tsCountAlwaysReturnValue) {
117,712✔
5047
    SET_VAL(GET_RES_INFO(pCtx), 0, 1);
1,860✔
5048
  } else {
5049
    SET_VAL(GET_RES_INFO(pCtx), 1, 1);
115,852✔
5050
  }
5051

5052
  return TSDB_CODE_SUCCESS;
117,712✔
5053
}
5054

5055
static void hllTransferInfo(SHLLInfo* pInput, SHLLInfo* pOutput) {
2,462✔
5056
  for (int32_t k = 0; k < HLL_BUCKETS; ++k) {
39,621,587✔
5057
    if (pOutput->buckets[k] < pInput->buckets[k]) {
39,619,125✔
5058
      pOutput->buckets[k] = pInput->buckets[k];
58,983✔
5059
    }
5060
  }
5061
  pOutput->totalCount += pInput->totalCount;
2,462✔
5062
}
2,462✔
5063

5064
int32_t hllFunctionMerge(SqlFunctionCtx* pCtx) {
2,462✔
5065
  SInputColumnInfoData* pInput = &pCtx->input;
2,462✔
5066
  SColumnInfoData*      pCol = pInput->pData[0];
2,462✔
5067

5068
  if (IS_NULL_TYPE(pCol->info.type)) {
2,462!
5069
    SET_VAL(GET_RES_INFO(pCtx), 0, 1);
×
5070
    return TSDB_CODE_SUCCESS;
×
5071
  }
5072

5073
  if (pCol->info.type != TSDB_DATA_TYPE_BINARY) {
2,462!
5074
    return TSDB_CODE_SUCCESS;
×
5075
  }
5076

5077
  SHLLInfo* pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
2,462✔
5078

5079
  int32_t start = pInput->startRowIndex;
2,462✔
5080

5081
  for (int32_t i = start; i < start + pInput->numOfRows; ++i) {
4,924✔
5082
    if (colDataIsNull_s(pCol, i)) continue;
4,924!
5083
    char*     data = colDataGetData(pCol, i);
2,462!
5084
    SHLLInfo* pInputInfo = (SHLLInfo*)varDataVal(data);
2,462✔
5085
    hllTransferInfo(pInputInfo, pInfo);
2,462✔
5086
  }
5087

5088
  if (pInfo->totalCount == 0 && !tsCountAlwaysReturnValue) {
2,462✔
5089
    SET_VAL(GET_RES_INFO(pCtx), 0, 1);
3✔
5090
  } else {
5091
    SET_VAL(GET_RES_INFO(pCtx), 1, 1);
2,459✔
5092
  }
5093

5094
  return TSDB_CODE_SUCCESS;
2,462✔
5095
}
5096

5097
int32_t hllFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
110,757✔
5098
  SResultRowEntryInfo* pInfo = GET_RES_INFO(pCtx);
110,757✔
5099

5100
  SHLLInfo* pHllInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
110,757✔
5101
  pHllInfo->result = hllCountCnt(pHllInfo->buckets);
110,757✔
5102
  if (tsCountAlwaysReturnValue && pHllInfo->result == 0) {
110,785✔
5103
    pInfo->numOfRes = 1;
6,179✔
5104
  }
5105

5106
  return functionFinalize(pCtx, pBlock);
110,785✔
5107
}
5108

5109
int32_t hllPartialFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
3,166✔
5110
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
3,166✔
5111
  SHLLInfo*            pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
3,166✔
5112
  int32_t              resultBytes = getHLLInfoSize();
3,166✔
5113
  char*                res = taosMemoryCalloc(resultBytes + VARSTR_HEADER_SIZE, sizeof(char));
3,166!
5114

5115
  if (NULL == res) {
3,167!
5116
    return terrno;
×
5117
  }
5118
  (void)memcpy(varDataVal(res), pInfo, resultBytes);
3,167✔
5119
  varDataSetLen(res, resultBytes);
3,167✔
5120

5121
  int32_t          slotId = pCtx->pExpr->base.resSchema.slotId;
3,167✔
5122
  int32_t          code = TSDB_CODE_SUCCESS;
3,167✔
5123
  SColumnInfoData* pCol = taosArrayGet(pBlock->pDataBlock, slotId);
3,167✔
5124
  if (NULL == pCol) {
3,167!
5125
    code = terrno;
×
5126
    goto _exit;
×
5127
  }
5128

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

5131
_exit:
3,167✔
5132
  taosMemoryFree(res);
3,167!
5133
  return code;
3,167✔
5134
}
5135

5136
int32_t hllCombine(SqlFunctionCtx* pDestCtx, SqlFunctionCtx* pSourceCtx) {
×
5137
  SResultRowEntryInfo* pDResInfo = GET_RES_INFO(pDestCtx);
×
5138
  SHLLInfo*            pDBuf = GET_ROWCELL_INTERBUF(pDResInfo);
×
5139

5140
  SResultRowEntryInfo* pSResInfo = GET_RES_INFO(pSourceCtx);
×
5141
  SHLLInfo*            pSBuf = GET_ROWCELL_INTERBUF(pSResInfo);
×
5142

5143
  hllTransferInfo(pSBuf, pDBuf);
×
5144
  pDResInfo->numOfRes = TMAX(pDResInfo->numOfRes, pSResInfo->numOfRes);
×
5145
  pDResInfo->isNullRes &= pSResInfo->isNullRes;
×
5146
  return TSDB_CODE_SUCCESS;
×
5147
}
5148

5149
bool getStateFuncEnv(SFunctionNode* UNUSED_PARAM(pFunc), SFuncExecEnv* pEnv) {
43,956✔
5150
  pEnv->calcMemSize = sizeof(SStateInfo);
43,956✔
5151
  return true;
43,956✔
5152
}
5153

5154
static int8_t getStateOpType(char* opStr) {
201,262✔
5155
  int8_t opType;
5156
  if (strncasecmp(opStr, "LT", 2) == 0) {
201,262✔
5157
    opType = STATE_OPER_LT;
6,387✔
5158
  } else if (strncasecmp(opStr, "GT", 2) == 0) {
194,875✔
5159
    opType = STATE_OPER_GT;
9,662✔
5160
  } else if (strncasecmp(opStr, "LE", 2) == 0) {
185,213✔
5161
    opType = STATE_OPER_LE;
992✔
5162
  } else if (strncasecmp(opStr, "GE", 2) == 0) {
184,221✔
5163
    opType = STATE_OPER_GE;
109,142✔
5164
  } else if (strncasecmp(opStr, "NE", 2) == 0) {
75,079✔
5165
    opType = STATE_OPER_NE;
55,600✔
5166
  } else if (strncasecmp(opStr, "EQ", 2) == 0) {
19,479!
5167
    opType = STATE_OPER_EQ;
19,479✔
5168
  } else {
5169
    opType = STATE_OPER_INVALID;
×
5170
  }
5171

5172
  return opType;
201,262✔
5173
}
5174

5175
static bool checkStateOp(int8_t op, SColumnInfoData* pCol, int32_t index, SVariant param) {
103,958,759✔
5176
  char* data = colDataGetData(pCol, index);
103,958,759!
5177
  switch (pCol->info.type) {
103,958,759!
5178
    case TSDB_DATA_TYPE_TINYINT: {
41,446,628✔
5179
      int8_t v = *(int8_t*)data;
41,446,628✔
5180
      STATE_COMP(op, v, param);
41,446,628!
5181
      break;
×
5182
    }
5183
    case TSDB_DATA_TYPE_UTINYINT: {
18,048✔
5184
      uint8_t v = *(uint8_t*)data;
18,048✔
5185
      STATE_COMP(op, v, param);
18,048!
5186
      break;
×
5187
    }
5188
    case TSDB_DATA_TYPE_SMALLINT: {
58,812✔
5189
      int16_t v = *(int16_t*)data;
58,812✔
5190
      STATE_COMP(op, v, param);
58,812!
5191
      break;
×
5192
    }
5193
    case TSDB_DATA_TYPE_USMALLINT: {
5,760✔
5194
      uint16_t v = *(uint16_t*)data;
5,760✔
5195
      STATE_COMP(op, v, param);
5,760!
5196
      break;
×
5197
    }
5198
    case TSDB_DATA_TYPE_INT: {
22,168✔
5199
      int32_t v = *(int32_t*)data;
22,168✔
5200
      STATE_COMP(op, v, param);
22,168!
5201
      break;
×
5202
    }
5203
    case TSDB_DATA_TYPE_UINT: {
5,760✔
5204
      uint32_t v = *(uint32_t*)data;
5,760✔
5205
      STATE_COMP(op, v, param);
5,760!
5206
      break;
×
5207
    }
5208
    case TSDB_DATA_TYPE_BIGINT: {
22,629,122✔
5209
      int64_t v = *(int64_t*)data;
22,629,122✔
5210
      STATE_COMP(op, v, param);
22,629,122!
5211
      break;
×
5212
    }
5213
    case TSDB_DATA_TYPE_UBIGINT: {
5,760✔
5214
      uint64_t v = *(uint64_t*)data;
5,760✔
5215
      STATE_COMP(op, v, param);
5,760!
5216
      break;
×
5217
    }
5218
    case TSDB_DATA_TYPE_FLOAT: {
12,169,030✔
5219
      float v = *(float*)data;
12,169,030✔
5220
      STATE_COMP(op, v, param);
12,169,030!
5221
      break;
×
5222
    }
5223
    case TSDB_DATA_TYPE_DOUBLE: {
27,597,996✔
5224
      double v = *(double*)data;
27,597,996✔
5225
      STATE_COMP(op, v, param);
27,597,996!
5226
      break;
×
5227
    }
5228
    default: {
×
5229
      return false;
×
5230
    }
5231
  }
5232
  return false;
×
5233
}
5234

5235
int32_t stateCountFunction(SqlFunctionCtx* pCtx) {
62,358✔
5236
  int32_t              code = TSDB_CODE_SUCCESS;
62,358✔
5237
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
62,358✔
5238
  SStateInfo*          pInfo = GET_ROWCELL_INTERBUF(pResInfo);
62,358✔
5239

5240
  SInputColumnInfoData* pInput = &pCtx->input;
62,358✔
5241
  TSKEY*                tsList = (int64_t*)pInput->pPTS->pData;
62,358✔
5242

5243
  SColumnInfoData* pInputCol = pInput->pData[0];
62,358✔
5244

5245
  int32_t          numOfElems = 0;
62,358✔
5246
  SColumnInfoData* pOutput = (SColumnInfoData*)pCtx->pOutput;
62,358✔
5247

5248
  int8_t op = getStateOpType(varDataVal(pCtx->param[1].param.pz));
62,358✔
5249
  if (STATE_OPER_INVALID == op) {
62,358!
5250
    return 0;
×
5251
  }
5252

5253
  for (int32_t i = pInput->startRowIndex; i < pInput->numOfRows + pInput->startRowIndex; i += 1) {
46,907,592✔
5254
    if (pInfo->isPrevTsSet == true && tsList[i] == pInfo->prevTs) {
46,845,237!
5255
      return TSDB_CODE_FUNC_DUP_TIMESTAMP;
×
5256
    } else {
5257
      pInfo->prevTs = tsList[i];
46,845,237✔
5258
    }
5259

5260
    pInfo->isPrevTsSet = true;
46,845,237✔
5261
    numOfElems++;
46,845,237✔
5262

5263
    if (colDataIsNull_f(pInputCol, i)) {
46,845,237✔
5264
      colDataSetNULL(pOutput, i);
87,524!
5265
      // handle selectivity
5266
      if (pCtx->subsidiaries.num > 0) {
87,524✔
5267
        code = appendSelectivityValue(pCtx, i, pCtx->offset + numOfElems - 1);
36✔
5268
        if (TSDB_CODE_SUCCESS != code) {
36!
5269
          return code;
×
5270
        }
5271
      }
5272
      continue;
87,524✔
5273
    }
5274

5275
    bool ret = checkStateOp(op, pInputCol, i, pCtx->param[2].param);
46,757,713✔
5276

5277
    int64_t output = -1;
46,757,674✔
5278
    if (ret) {
46,757,674✔
5279
      output = ++pInfo->count;
7,533,116✔
5280
    } else {
5281
      pInfo->count = 0;
39,224,558✔
5282
    }
5283
    code = colDataSetVal(pOutput, pCtx->offset + numOfElems - 1, (char*)&output, false);
46,757,674✔
5284
    if (TSDB_CODE_SUCCESS != code) {
46,757,710!
5285
      return code;
×
5286
    }
5287

5288
    // handle selectivity
5289
    if (pCtx->subsidiaries.num > 0) {
46,757,710✔
5290
      code = appendSelectivityValue(pCtx, i, pCtx->offset + numOfElems - 1);
23,742,484✔
5291
      if (TSDB_CODE_SUCCESS != code) {
23,742,484!
5292
        return code;
×
5293
      }
5294
    }
5295
  }
5296

5297
  pResInfo->numOfRes = numOfElems;
62,355✔
5298
  return TSDB_CODE_SUCCESS;
62,355✔
5299
}
5300

5301
int32_t stateDurationFunction(SqlFunctionCtx* pCtx) {
138,904✔
5302
  int32_t              code = TSDB_CODE_SUCCESS;
138,904✔
5303
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
138,904✔
5304
  SStateInfo*          pInfo = GET_ROWCELL_INTERBUF(pResInfo);
138,904✔
5305

5306
  SInputColumnInfoData* pInput = &pCtx->input;
138,904✔
5307
  TSKEY*                tsList = (int64_t*)pInput->pPTS->pData;
138,904✔
5308

5309
  SColumnInfoData* pInputCol = pInput->pData[0];
138,904✔
5310

5311
  int32_t          numOfElems = 0;
138,904✔
5312
  SColumnInfoData* pOutput = (SColumnInfoData*)pCtx->pOutput;
138,904✔
5313

5314
  // TODO: process timeUnit for different db precisions
5315
  int32_t timeUnit = 1;
138,904✔
5316
  if (pCtx->numOfParams == 5) {  // TODO: param number incorrect
138,904✔
5317
    timeUnit = pCtx->param[3].param.i;
136,944✔
5318
  }
5319

5320
  int8_t op = getStateOpType(varDataVal(pCtx->param[1].param.pz));
138,904✔
5321
  if (STATE_OPER_INVALID == op) {
138,904!
5322
    return TSDB_CODE_INVALID_PARA;
×
5323
  }
5324

5325
  for (int32_t i = pInput->startRowIndex; i < pInput->numOfRows + pInput->startRowIndex; i += 1) {
57,561,060✔
5326
    if (pInfo->isPrevTsSet == true && tsList[i] == pInfo->prevTs) {
57,422,156!
5327
      return TSDB_CODE_FUNC_DUP_TIMESTAMP;
×
5328
    } else {
5329
      pInfo->prevTs = tsList[i];
57,422,156✔
5330
    }
5331

5332
    pInfo->isPrevTsSet = true;
57,422,156✔
5333
    numOfElems++;
57,422,156✔
5334

5335
    if (colDataIsNull_f(pInputCol, i)) {
57,422,156!
5336
      colDataSetNULL(pOutput, i);
221,020!
5337
      // handle selectivity
5338
      if (pCtx->subsidiaries.num > 0) {
221,020✔
5339
        code = appendSelectivityValue(pCtx, i, pCtx->offset + numOfElems - 1);
52✔
5340
        if (TSDB_CODE_SUCCESS != code) {
52!
5341
          return code;
×
5342
        }
5343
      }
5344
      continue;
221,020✔
5345
    }
5346

5347
    bool    ret = checkStateOp(op, pInputCol, i, pCtx->param[2].param);
57,201,136✔
5348
    int64_t output = -1;
57,201,136✔
5349
    if (ret) {
57,201,136✔
5350
      if (pInfo->durationStart == 0) {
34,100,371✔
5351
        output = 0;
11,308,460✔
5352
        pInfo->durationStart = tsList[i];
11,308,460✔
5353
      } else {
5354
        output = (tsList[i] - pInfo->durationStart) / timeUnit;
22,791,911✔
5355
      }
5356
    } else {
5357
      pInfo->durationStart = 0;
23,100,765✔
5358
    }
5359
    code = colDataSetVal(pOutput, pCtx->offset + numOfElems - 1, (char*)&output, false);
57,201,136✔
5360
    if (TSDB_CODE_SUCCESS != code) {
57,201,136!
5361
      return code;
×
5362
    }
5363

5364
    // handle selectivity
5365
    if (pCtx->subsidiaries.num > 0) {
57,201,136✔
5366
      code = appendSelectivityValue(pCtx, i, pCtx->offset + numOfElems - 1);
36,634,236✔
5367
      if (TSDB_CODE_SUCCESS != code) {
36,634,236!
5368
        return code;
×
5369
      }
5370
    }
5371
  }
5372

5373
  pResInfo->numOfRes = numOfElems;
138,904✔
5374
  return TSDB_CODE_SUCCESS;
138,904✔
5375
}
5376

5377
bool getCsumFuncEnv(SFunctionNode* UNUSED_PARAM(pFunc), SFuncExecEnv* pEnv) {
34,754✔
5378
  pEnv->calcMemSize = sizeof(SSumRes);
34,754✔
5379
  return true;
34,754✔
5380
}
5381

5382
int32_t csumFunction(SqlFunctionCtx* pCtx) {
55,150✔
5383
  int32_t              code = TSDB_CODE_SUCCESS;
55,150✔
5384
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
55,150✔
5385
  SSumRes*             pSumRes = GET_ROWCELL_INTERBUF(pResInfo);
55,150✔
5386

5387
  SInputColumnInfoData* pInput = &pCtx->input;
55,150✔
5388
  TSKEY*                tsList = (int64_t*)pInput->pPTS->pData;
55,150✔
5389

5390
  SColumnInfoData* pInputCol = pInput->pData[0];
55,150✔
5391
  SColumnInfoData* pOutput = (SColumnInfoData*)pCtx->pOutput;
55,150✔
5392

5393
  int32_t numOfElems = 0;
55,150✔
5394
  int32_t type = pInputCol->info.type;
55,150✔
5395
  int32_t startOffset = pCtx->offset;
55,150✔
5396
  for (int32_t i = pInput->startRowIndex; i < pInput->numOfRows + pInput->startRowIndex; i += 1) {
9,890,600✔
5397
    if (pSumRes->isPrevTsSet == true && tsList[i] == pSumRes->prevTs) {
9,837,925✔
5398
      return TSDB_CODE_FUNC_DUP_TIMESTAMP;
18✔
5399
    } else {
5400
      pSumRes->prevTs = tsList[i];
9,837,907✔
5401
    }
5402
    pSumRes->isPrevTsSet = true;
9,837,907✔
5403

5404
    int32_t pos = startOffset + numOfElems;
9,837,907✔
5405
    if (colDataIsNull_f(pInputCol, i)) {
9,837,907✔
5406
      // colDataSetNULL(pOutput, i);
5407
      continue;
326,948✔
5408
    }
5409

5410
    char* data = colDataGetData(pInputCol, i);
9,510,959!
5411
    if (IS_SIGNED_NUMERIC_TYPE(type)) {
17,545,307!
5412
      int64_t v;
5413
      GET_TYPED_DATA(v, int64_t, type, data, typeGetTypeModFromColInfo(&pInputCol->info));
8,036,581!
5414
      pSumRes->isum += v;
8,036,581✔
5415
      code = colDataSetVal(pOutput, pos, (char*)&pSumRes->isum, false);
8,036,581✔
5416
      if (TSDB_CODE_SUCCESS != code) {
8,034,348!
5417
        return code;
×
5418
      }
5419
    } else if (IS_UNSIGNED_NUMERIC_TYPE(type)) {
1,481,082!
5420
      uint64_t v;
5421
      GET_TYPED_DATA(v, uint64_t, type, data, typeGetTypeModFromColInfo(&pInputCol->info));
6,704!
5422
      pSumRes->usum += v;
6,704✔
5423
      code = colDataSetVal(pOutput, pos, (char*)&pSumRes->usum, false);
6,704✔
5424
      if (TSDB_CODE_SUCCESS != code) {
6,704!
5425
        return code;
×
5426
      }
5427
    } else if (IS_FLOAT_TYPE(type)) {
1,467,674!
5428
      double v;
5429
      GET_TYPED_DATA(v, double, type, data, typeGetTypeModFromColInfo(&pInputCol->info));
1,479,710!
5430
      pSumRes->dsum += v;
1,479,631✔
5431
      // check for overflow
5432
      if (isinf(pSumRes->dsum) || isnan(pSumRes->dsum)) {
1,479,631!
5433
        colDataSetNULL(pOutput, pos);
6!
5434
      } else {
5435
        code = colDataSetVal(pOutput, pos, (char*)&pSumRes->dsum, false);
1,479,625✔
5436
        if (TSDB_CODE_SUCCESS != code) {
1,479,638!
5437
          return code;
×
5438
        }
5439
      }
5440
    }
5441

5442
    // handle selectivity
5443
    if (pCtx->subsidiaries.num > 0) {
9,508,660✔
5444
      code = appendSelectivityValue(pCtx, i, pos);
6,030,015✔
5445
      if (TSDB_CODE_SUCCESS != code) {
6,029,857!
5446
        return code;
×
5447
      }
5448
    }
5449

5450
    numOfElems++;
9,508,502✔
5451
  }
5452

5453
  pResInfo->numOfRes = numOfElems;
52,675✔
5454
  return TSDB_CODE_SUCCESS;
52,675✔
5455
}
5456

5457
bool getMavgFuncEnv(SFunctionNode* UNUSED_PARAM(pFunc), SFuncExecEnv* pEnv) {
31,848✔
5458
  pEnv->calcMemSize = sizeof(SMavgInfo) + MAVG_MAX_POINTS_NUM * sizeof(double);
31,848✔
5459
  return true;
31,848✔
5460
}
5461

5462
int32_t mavgFunctionSetup(SqlFunctionCtx* pCtx, SResultRowEntryInfo* pResultInfo) {
572,455✔
5463
  if (pResultInfo->initialized) {
572,455✔
5464
    return TSDB_CODE_SUCCESS;
540,000✔
5465
  }
5466
  if (TSDB_CODE_SUCCESS != functionSetup(pCtx, pResultInfo)) {
32,455!
5467
    return TSDB_CODE_FUNC_SETUP_ERROR;
×
5468
  }
5469

5470
  SMavgInfo* pInfo = GET_ROWCELL_INTERBUF(pResultInfo);
32,456✔
5471
  pInfo->pos = 0;
32,456✔
5472
  pInfo->sum = 0;
32,456✔
5473
  pInfo->prevTs = -1;
32,456✔
5474
  pInfo->isPrevTsSet = false;
32,456✔
5475
  pInfo->numOfPoints = pCtx->param[1].param.i;
32,456✔
5476
  if (pInfo->numOfPoints < 1 || pInfo->numOfPoints > MAVG_MAX_POINTS_NUM) {
32,456!
5477
    return TSDB_CODE_FUNC_FUNTION_PARA_VALUE;
×
5478
  }
5479
  pInfo->pointsMeet = false;
32,456✔
5480

5481
  return TSDB_CODE_SUCCESS;
32,456✔
5482
}
5483

5484
int32_t mavgFunction(SqlFunctionCtx* pCtx) {
540,607✔
5485
  int32_t              code = TSDB_CODE_SUCCESS;
540,607✔
5486
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
540,607✔
5487
  SMavgInfo*           pInfo = GET_ROWCELL_INTERBUF(pResInfo);
540,607✔
5488

5489
  SInputColumnInfoData* pInput = &pCtx->input;
540,607✔
5490
  TSKEY*                tsList = (int64_t*)pInput->pPTS->pData;
540,607✔
5491

5492
  SColumnInfoData* pInputCol = pInput->pData[0];
540,607✔
5493
  SColumnInfoData* pTsOutput = pCtx->pTsOutput;
540,607✔
5494
  SColumnInfoData* pOutput = (SColumnInfoData*)pCtx->pOutput;
540,607✔
5495

5496
  int32_t numOfElems = 0;
540,607✔
5497
  int32_t type = pInputCol->info.type;
540,607✔
5498
  int32_t startOffset = pCtx->offset;
540,607✔
5499
  for (int32_t i = pInput->startRowIndex; i < pInput->numOfRows + pInput->startRowIndex; i += 1) {
175,788,083✔
5500
    if (pInfo->isPrevTsSet == true && tsList[i] == pInfo->prevTs) {
175,247,221!
5501
      return TSDB_CODE_FUNC_DUP_TIMESTAMP;
×
5502
    } else {
5503
      pInfo->prevTs = tsList[i];
175,247,221✔
5504
    }
5505
    pInfo->isPrevTsSet = true;
175,247,221✔
5506

5507
    int32_t pos = startOffset + numOfElems;
175,247,221✔
5508
    if (colDataIsNull_f(pInputCol, i)) {
175,247,221✔
5509
      // colDataSetNULL(pOutput, i);
5510
      continue;
139,348✔
5511
    }
5512

5513
    char*  data = colDataGetData(pInputCol, i);
175,107,873!
5514
    double v;
5515
    GET_TYPED_DATA(v, double, type, data, typeGetTypeModFromColInfo(&pInputCol->info));
175,107,873!
5516

5517
    if (!pInfo->pointsMeet && (pInfo->pos < pInfo->numOfPoints - 1)) {
175,108,126✔
5518
      pInfo->points[pInfo->pos] = v;
14,627,127✔
5519
      pInfo->sum += v;
14,627,127✔
5520
    } else {
5521
      if (!pInfo->pointsMeet && (pInfo->pos == pInfo->numOfPoints - 1)) {
160,480,999!
5522
        pInfo->sum += v;
30,671✔
5523
        pInfo->pointsMeet = true;
30,671✔
5524
      } else {
5525
        pInfo->sum = pInfo->sum + v - pInfo->points[pInfo->pos];
160,450,328✔
5526
      }
5527

5528
      pInfo->points[pInfo->pos] = v;
160,480,999✔
5529
      double result = pInfo->sum / pInfo->numOfPoints;
160,480,999✔
5530
      // check for overflow
5531
      if (isinf(result) || isnan(result)) {
160,480,999!
5532
        colDataSetNULL(pOutput, pos);
3!
5533
      } else {
5534
        code = colDataSetVal(pOutput, pos, (char*)&result, false);
160,480,996✔
5535
        if (TSDB_CODE_SUCCESS != code) {
160,480,998!
5536
          return code;
×
5537
        }
5538
      }
5539

5540
      // handle selectivity
5541
      if (pCtx->subsidiaries.num > 0) {
160,481,001✔
5542
        code = appendSelectivityValue(pCtx, i, pos);
100,644,558✔
5543
        if (TSDB_CODE_SUCCESS != code) {
100,644,558!
5544
          return code;
×
5545
        }
5546
      }
5547

5548
      numOfElems++;
160,481,001✔
5549
    }
5550

5551
    pInfo->pos++;
175,108,128✔
5552
    if (pInfo->pos == pInfo->numOfPoints) {
175,108,128✔
5553
      pInfo->pos = 0;
580,814✔
5554
    }
5555
  }
5556

5557
  pResInfo->numOfRes = numOfElems;
540,862✔
5558
  return TSDB_CODE_SUCCESS;
540,862✔
5559
}
5560

5561
static SSampleInfo* getSampleOutputInfo(SqlFunctionCtx* pCtx) {
42,967,554✔
5562
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
42,967,554✔
5563
  SSampleInfo*         pInfo = GET_ROWCELL_INTERBUF(pResInfo);
42,967,554✔
5564

5565
  pInfo->data = (char*)pInfo + sizeof(SSampleInfo);
42,967,554✔
5566
  pInfo->tuplePos = (STuplePos*)((char*)pInfo + sizeof(SSampleInfo) + pInfo->samples * pInfo->colBytes);
42,967,554✔
5567

5568
  return pInfo;
42,967,554✔
5569
}
5570

5571
bool getSampleFuncEnv(SFunctionNode* pFunc, SFuncExecEnv* pEnv) {
77,016✔
5572
  SColumnNode* pCol = (SColumnNode*)nodesListGetNode(pFunc->pParameterList, 0);
77,016✔
5573
  SValueNode*  pVal = (SValueNode*)nodesListGetNode(pFunc->pParameterList, 1);
77,022✔
5574
  int32_t      numOfSamples = pVal->datum.i;
77,037✔
5575
  pEnv->calcMemSize = sizeof(SSampleInfo) + numOfSamples * (pCol->node.resType.bytes + sizeof(STuplePos));
77,037✔
5576
  return true;
77,037✔
5577
}
5578

5579
int32_t sampleFunctionSetup(SqlFunctionCtx* pCtx, SResultRowEntryInfo* pResultInfo) {
21,663,194✔
5580
  if (pResultInfo->initialized) {
21,663,194!
5581
    return TSDB_CODE_SUCCESS;
×
5582
  }
5583
  if (TSDB_CODE_SUCCESS != functionSetup(pCtx, pResultInfo)) {
21,663,194!
5584
    return TSDB_CODE_FUNC_SETUP_ERROR;
×
5585
  }
5586

5587
  taosSeedRand(taosSafeRand());
21,663,202✔
5588

5589
  SSampleInfo* pInfo = GET_ROWCELL_INTERBUF(pResultInfo);
21,663,210✔
5590
  pInfo->samples = pCtx->param[1].param.i;
21,663,210✔
5591
  pInfo->totalPoints = 0;
21,663,210✔
5592
  pInfo->numSampled = 0;
21,663,210✔
5593
  pInfo->colType = pCtx->resDataInfo.type;
21,663,210✔
5594
  pInfo->colBytes = pCtx->resDataInfo.bytes;
21,663,210✔
5595
  pInfo->nullTuplePos.pageId = -1;
21,663,210✔
5596
  pInfo->nullTupleSaved = false;
21,663,210✔
5597
  pInfo->data = (char*)pInfo + sizeof(SSampleInfo);
21,663,210✔
5598
  pInfo->tuplePos = (STuplePos*)((char*)pInfo + sizeof(SSampleInfo) + pInfo->samples * pInfo->colBytes);
21,663,210✔
5599

5600
  return TSDB_CODE_SUCCESS;
21,663,210✔
5601
}
5602

5603
static void sampleAssignResult(SSampleInfo* pInfo, char* data, int32_t index) {
41,895,590✔
5604
  assignVal(pInfo->data + index * pInfo->colBytes, data, pInfo->colBytes, pInfo->colType);
41,895,590✔
5605
}
41,895,751✔
5606

5607
static int32_t doReservoirSample(SqlFunctionCtx* pCtx, SSampleInfo* pInfo, char* data, int32_t index) {
47,960,436✔
5608
  pInfo->totalPoints++;
47,960,436✔
5609
  if (pInfo->numSampled < pInfo->samples) {
47,960,436✔
5610
    sampleAssignResult(pInfo, data, pInfo->numSampled);
37,752,628✔
5611
    if (pCtx->subsidiaries.num > 0) {
37,752,923✔
5612
      int32_t code = saveTupleData(pCtx, index, pCtx->pSrcBlock, &pInfo->tuplePos[pInfo->numSampled]);
3,007,316✔
5613
      if (code != TSDB_CODE_SUCCESS) {
3,007,358!
5614
        return code;
×
5615
      }
5616
    }
5617
    pInfo->numSampled++;
37,752,965✔
5618
  } else {
5619
    int32_t j = taosRand() % (pInfo->totalPoints);
10,207,808✔
5620
    if (j < pInfo->samples) {
10,213,547✔
5621
      sampleAssignResult(pInfo, data, j);
4,144,402✔
5622
      if (pCtx->subsidiaries.num > 0) {
4,144,368✔
5623
        int32_t code = updateTupleData(pCtx, index, pCtx->pSrcBlock, &pInfo->tuplePos[j]);
1,892,938✔
5624
        if (code != TSDB_CODE_SUCCESS) {
1,888,017!
5625
          return code;
×
5626
        }
5627
      }
5628
    }
5629
  }
5630

5631
  return TSDB_CODE_SUCCESS;
47,961,557✔
5632
}
5633

5634
int32_t sampleFunction(SqlFunctionCtx* pCtx) {
21,714,978✔
5635
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
21,714,978✔
5636
  SSampleInfo*         pInfo = getSampleOutputInfo(pCtx);
21,714,978✔
5637

5638
  SInputColumnInfoData* pInput = &pCtx->input;
21,714,965✔
5639

5640
  SColumnInfoData* pInputCol = pInput->pData[0];
21,714,965✔
5641
  for (int32_t i = pInput->startRowIndex; i < pInput->numOfRows + pInput->startRowIndex; i += 1) {
70,011,715✔
5642
    if (colDataIsNull_s(pInputCol, i)) {
96,600,424✔
5643
      continue;
335,960✔
5644
    }
5645

5646
    char*   data = colDataGetData(pInputCol, i);
47,964,252!
5647
    int32_t code = doReservoirSample(pCtx, pInfo, data, i);
47,964,252✔
5648
    if (code != TSDB_CODE_SUCCESS) {
47,960,790!
5649
      return code;
×
5650
    }
5651
  }
5652

5653
  if (pInfo->numSampled == 0 && pCtx->subsidiaries.num > 0 && !pInfo->nullTupleSaved) {
21,711,503✔
5654
    int32_t code = saveTupleData(pCtx, pInput->startRowIndex, pCtx->pSrcBlock, &pInfo->nullTuplePos);
19✔
5655
    if (code != TSDB_CODE_SUCCESS) {
19!
5656
      return code;
×
5657
    }
5658
    pInfo->nullTupleSaved = true;
19✔
5659
  }
5660

5661
  SET_VAL(pResInfo, pInfo->numSampled, pInfo->numSampled);
21,711,503✔
5662
  return TSDB_CODE_SUCCESS;
21,711,503✔
5663
}
5664

5665
int32_t sampleFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
21,252,595✔
5666
  int32_t              code = TSDB_CODE_SUCCESS;
21,252,595✔
5667
  SResultRowEntryInfo* pEntryInfo = GET_RES_INFO(pCtx);
21,252,595✔
5668

5669
  SSampleInfo* pInfo = getSampleOutputInfo(pCtx);
21,252,595✔
5670
  pEntryInfo->complete = true;
21,252,598✔
5671

5672
  int32_t          slotId = pCtx->pExpr->base.resSchema.slotId;
21,252,598✔
5673
  SColumnInfoData* pCol = taosArrayGet(pBlock->pDataBlock, slotId);
21,252,598✔
5674
  if (NULL == pCol) {
21,252,583!
5675
    return TSDB_CODE_OUT_OF_RANGE;
×
5676
  }
5677

5678
  int32_t currentRow = pBlock->info.rows;
21,252,583✔
5679
  if (pInfo->numSampled == 0) {
21,252,583✔
5680
    colDataSetNULL(pCol, currentRow);
2,149✔
5681
    code = setSelectivityValue(pCtx, pBlock, &pInfo->nullTuplePos, currentRow);
2,149✔
5682
    return code;
2,149✔
5683
  }
5684
  for (int32_t i = 0; i < pInfo->numSampled; ++i) {
58,364,008✔
5685
    code = colDataSetVal(pCol, currentRow + i, pInfo->data + i * pInfo->colBytes, false);
37,117,610✔
5686
    if (TSDB_CODE_SUCCESS != code) {
37,111,210!
5687
      return code;
×
5688
    }
5689
    code = setSelectivityValue(pCtx, pBlock, &pInfo->tuplePos[i], currentRow + i);
37,111,210✔
5690
    if (TSDB_CODE_SUCCESS != code) {
37,113,574!
5691
      return code;
×
5692
    }
5693
  }
5694

5695
  return code;
21,246,398✔
5696
}
5697

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

5708
int32_t tailFunctionSetup(SqlFunctionCtx* pCtx, SResultRowEntryInfo* pResultInfo) {
×
5709
#if 0
5710
  if (!functionSetup(pCtx, pResultInfo)) {
5711
    return false;
5712
  }
5713

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

5729
  pInfo->pItems = (STailItem**)((char*)pInfo + sizeof(STailInfo));
5730
  char* pItem = (char*)pInfo->pItems + pInfo->numOfPoints * POINTER_BYTES;
5731

5732
  size_t unitSize = sizeof(STailItem) + pInfo->colBytes;
5733
  for (int32_t i = 0; i < pInfo->numOfPoints; ++i) {
5734
    pInfo->pItems[i] = (STailItem*)(pItem + i * unitSize);
5735
    pInfo->pItems[i]->isNull = false;
5736
  }
5737
#endif
5738

5739
  return TSDB_CODE_SUCCESS;
×
5740
}
5741

5742
static void tailAssignResult(STailItem* pItem, char* data, int32_t colBytes, TSKEY ts, bool isNull) {
×
5743
#if 0
5744
  pItem->timestamp = ts;
5745
  if (isNull) {
5746
    pItem->isNull = true;
5747
  } else {
5748
    pItem->isNull = false;
5749
    memcpy(pItem->data, data, colBytes);
5750
  }
5751
#endif
5752
}
×
5753

5754
#if 0
5755
static int32_t tailCompFn(const void* p1, const void* p2, const void* param) {
5756
  STailItem* d1 = *(STailItem**)p1;
5757
  STailItem* d2 = *(STailItem**)p2;
5758
  return compareInt64Val(&d1->timestamp, &d2->timestamp);
5759
}
5760

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

5774
int32_t tailFunction(SqlFunctionCtx* pCtx) {
×
5775
#if 0
5776
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
5777
  STailInfo*           pInfo = GET_ROWCELL_INTERBUF(pResInfo);
5778

5779
  SInputColumnInfoData* pInput = &pCtx->input;
5780
  TSKEY*                tsList = (int64_t*)pInput->pPTS->pData;
5781

5782
  SColumnInfoData* pInputCol = pInput->pData[0];
5783
  SColumnInfoData* pOutput = (SColumnInfoData*)pCtx->pOutput;
5784

5785
  int32_t startOffset = pCtx->offset;
5786
  if (pInfo->offset >= pInput->numOfRows) {
5787
    return 0;
5788
  } else {
5789
    pInfo->numOfPoints = TMIN(pInfo->numOfPoints, pInput->numOfRows - pInfo->offset);
5790
  }
5791
  for (int32_t i = pInput->startRowIndex; i < pInput->numOfRows + pInput->startRowIndex - pInfo->offset; i += 1) {
5792
    char* data = colDataGetData(pInputCol, i);
5793
    doTailAdd(pInfo, data, tsList[i], colDataIsNull_s(pInputCol, i));
5794
  }
5795

5796
  taosqsort(pInfo->pItems, pInfo->numOfPoints, POINTER_BYTES, NULL, tailCompFn);
5797

5798
  for (int32_t i = 0; i < pInfo->numOfPoints; ++i) {
5799
    int32_t    pos = startOffset + i;
5800
    STailItem* pItem = pInfo->pItems[i];
5801
    if (pItem->isNull) {
5802
      colDataSetNULL(pOutput, pos);
5803
    } else {
5804
      colDataSetVal(pOutput, pos, pItem->data, false);
5805
    }
5806
  }
5807

5808
  return pInfo->numOfPoints;
5809
#endif
5810
  return 0;
×
5811
}
5812

5813
int32_t tailFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
×
5814
#if 0
5815
  SResultRowEntryInfo* pEntryInfo = GET_RES_INFO(pCtx);
5816
  STailInfo*           pInfo = GET_ROWCELL_INTERBUF(pEntryInfo);
5817
  pEntryInfo->complete = true;
5818

5819
  int32_t type = pCtx->input.pData[0]->info.type;
5820
  int32_t slotId = pCtx->pExpr->base.resSchema.slotId;
5821

5822
  SColumnInfoData* pCol = taosArrayGet(pBlock->pDataBlock, slotId);
5823

5824
  // todo assign the tag value and the corresponding row data
5825
  int32_t currentRow = pBlock->info.rows;
5826
  for (int32_t i = 0; i < pEntryInfo->numOfRes; ++i) {
5827
    STailItem* pItem = pInfo->pItems[i];
5828
    colDataSetVal(pCol, currentRow, pItem->data, false);
5829
    currentRow += 1;
5830
  }
5831

5832
  return pEntryInfo->numOfRes;
5833
#endif
5834
  return 0;
×
5835
}
5836

5837
bool getUniqueFuncEnv(SFunctionNode* pFunc, SFuncExecEnv* pEnv) {
×
5838
#if 0
5839
  pEnv->calcMemSize = sizeof(SUniqueInfo) + UNIQUE_MAX_RESULT_SIZE;
5840
#endif
5841
  return true;
×
5842
}
5843

5844
int32_t uniqueFunctionSetup(SqlFunctionCtx* pCtx, SResultRowEntryInfo* pResInfo) {
×
5845
#if 0
5846
  if (!functionSetup(pCtx, pResInfo)) {
5847
    return false;
5848
  }
5849

5850
  SUniqueInfo* pInfo = GET_ROWCELL_INTERBUF(pResInfo);
5851
  pInfo->numOfPoints = 0;
5852
  pInfo->colType = pCtx->resDataInfo.type;
5853
  pInfo->colBytes = pCtx->resDataInfo.bytes;
5854
  if (pInfo->pHash != NULL) {
5855
    taosHashClear(pInfo->pHash);
5856
  } else {
5857
    pInfo->pHash = taosHashInit(64, taosGetDefaultHashFunction(TSDB_DATA_TYPE_BINARY), true, HASH_NO_LOCK);
5858
  }
5859
#endif
5860
  return TSDB_CODE_SUCCESS;
×
5861
}
5862

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

5880
  int32_t      hashKeyBytes = IS_VAR_DATA_TYPE(pInfo->colType) ? varDataTLen(data) : pInfo->colBytes;
5881
  SUniqueItem* pHashItem = taosHashGet(pInfo->pHash, data, hashKeyBytes);
5882
  if (pHashItem == NULL) {
5883
    int32_t      size = sizeof(SUniqueItem) + pInfo->colBytes;
5884
    SUniqueItem* pItem = (SUniqueItem*)(pInfo->pItems + pInfo->numOfPoints * size);
5885
    pItem->timestamp = ts;
5886
    memcpy(pItem->data, data, pInfo->colBytes);
5887

5888
    taosHashPut(pInfo->pHash, data, hashKeyBytes, (char*)pItem, sizeof(SUniqueItem*));
5889
    pInfo->numOfPoints++;
5890
  } else if (pHashItem->timestamp > ts) {
5891
    pHashItem->timestamp = ts;
5892
  }
5893
}
5894
#endif
5895

5896
int32_t uniqueFunction(SqlFunctionCtx* pCtx) {
×
5897
#if 0
5898
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
5899
  SUniqueInfo*         pInfo = GET_ROWCELL_INTERBUF(pResInfo);
5900

5901
  SInputColumnInfoData* pInput = &pCtx->input;
5902
  TSKEY*                tsList = (int64_t*)pInput->pPTS->pData;
5903

5904
  SColumnInfoData* pInputCol = pInput->pData[0];
5905
  SColumnInfoData* pTsOutput = pCtx->pTsOutput;
5906
  SColumnInfoData* pOutput = (SColumnInfoData*)pCtx->pOutput;
5907

5908
  int32_t startOffset = pCtx->offset;
5909
  for (int32_t i = pInput->startRowIndex; i < pInput->numOfRows + pInput->startRowIndex; ++i) {
5910
    char* data = colDataGetData(pInputCol, i);
5911
    doUniqueAdd(pInfo, data, tsList[i], colDataIsNull_s(pInputCol, i));
5912

5913
    if (sizeof(SUniqueInfo) + pInfo->numOfPoints * (sizeof(SUniqueItem) + pInfo->colBytes) >= UNIQUE_MAX_RESULT_SIZE) {
5914
      taosHashCleanup(pInfo->pHash);
5915
      return 0;
5916
    }
5917
  }
5918

5919
  for (int32_t i = 0; i < pInfo->numOfPoints; ++i) {
5920
    SUniqueItem* pItem = (SUniqueItem*)(pInfo->pItems + i * (sizeof(SUniqueItem) + pInfo->colBytes));
5921
    if (pItem->isNull == true) {
5922
      colDataSetNULL(pOutput, i);
5923
    } else {
5924
      colDataSetVal(pOutput, i, pItem->data, false);
5925
    }
5926
    if (pTsOutput != NULL) {
5927
      colDataSetInt64(pTsOutput, i, &pItem->timestamp);
5928
    }
5929
  }
5930

5931
  return pInfo->numOfPoints;
5932
#endif
5933
  return 0;
×
5934
}
5935

5936
bool getModeFuncEnv(SFunctionNode* pFunc, SFuncExecEnv* pEnv) {
61,511✔
5937
  pEnv->calcMemSize = sizeof(SModeInfo);
61,511✔
5938
  return true;
61,511✔
5939
}
5940

5941
int32_t modeFunctionSetup(SqlFunctionCtx* pCtx, SResultRowEntryInfo* pResInfo) {
53,636✔
5942
  if (pResInfo->initialized) {
53,636!
5943
    return TSDB_CODE_SUCCESS;
×
5944
  }
5945
  if (TSDB_CODE_SUCCESS != functionSetup(pCtx, pResInfo)) {
53,636!
5946
    return TSDB_CODE_FUNC_SETUP_ERROR;
×
5947
  }
5948

5949
  SModeInfo* pInfo = GET_ROWCELL_INTERBUF(pResInfo);
53,635✔
5950
  pInfo->colType = pCtx->resDataInfo.type;
53,635✔
5951
  pInfo->colBytes = pCtx->resDataInfo.bytes;
53,635✔
5952
  if (pInfo->pHash != NULL) {
53,635!
5953
    taosHashClear(pInfo->pHash);
×
5954
  } else {
5955
    pInfo->pHash = taosHashInit(64, taosGetDefaultHashFunction(TSDB_DATA_TYPE_BINARY), true, HASH_NO_LOCK);
53,635✔
5956
    if (NULL == pInfo->pHash) {
53,637!
5957
      return terrno;
×
5958
    }
5959
  }
5960
  pInfo->nullTupleSaved = false;
53,637✔
5961
  pInfo->nullTuplePos.pageId = -1;
53,637✔
5962

5963
  pInfo->buf = taosMemoryMalloc(pInfo->colBytes);
53,637!
5964
  if (NULL == pInfo->buf) {
53,637!
5965
    taosHashCleanup(pInfo->pHash);
×
5966
    pInfo->pHash = NULL;
×
5967
    return terrno;
×
5968
  }
5969
  pCtx->needCleanup = true;
53,637✔
5970
  return TSDB_CODE_SUCCESS;
53,637✔
5971
}
5972

5973
static void modeFunctionCleanup(SModeInfo* pInfo) {
53,637✔
5974
  taosHashCleanup(pInfo->pHash);
53,637✔
5975
  pInfo->pHash = NULL;
53,636✔
5976
  taosMemoryFreeClear(pInfo->buf);
53,636!
5977
}
53,635✔
5978

5979
void modeFunctionCleanupExt(SqlFunctionCtx* pCtx) {
×
5980
  if (pCtx == NULL || GET_RES_INFO(pCtx) == NULL || GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx)) == NULL) {
×
5981
    return;
×
5982
  }
5983
  modeFunctionCleanup(GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx)));
×
5984
}
5985

5986
static int32_t saveModeTupleData(SqlFunctionCtx* pCtx, char* data, SModeInfo* pInfo, STuplePos* pPos) {
107,306,710✔
5987
  if (IS_VAR_DATA_TYPE(pInfo->colType)) {
107,306,710!
5988
    if (pInfo->colType == TSDB_DATA_TYPE_JSON) {
26,526,215✔
5989
      (void)memcpy(pInfo->buf, data, getJsonValueLen(data));
1,188✔
5990
    } else if (IS_STR_DATA_BLOB(pInfo->colType)) {
26,525,027!
5991
      (void)memcpy(pInfo->buf, data, blobDataTLen(data));
×
5992
    } else {
5993
      (void)memcpy(pInfo->buf, data, varDataTLen(data));
26,525,042✔
5994
    }
5995
  } else {
5996
    (void)memcpy(pInfo->buf, data, pInfo->colBytes);
80,780,495✔
5997
  }
5998

5999
  return doSaveTupleData(&pCtx->saveHandle, pInfo->buf, pInfo->colBytes, NULL, pPos, pCtx->pStore);
107,306,710✔
6000
}
6001

6002
static int32_t doModeAdd(SModeInfo* pInfo, int32_t rowIndex, SqlFunctionCtx* pCtx, char* data) {
148,013,198✔
6003
  int32_t code = TSDB_CODE_SUCCESS;
148,013,198✔
6004
  int32_t hashKeyBytes;
6005
  if (IS_VAR_DATA_TYPE(pInfo->colType)) {
148,013,198!
6006
    hashKeyBytes = calcStrBytesByType(pInfo->colType, data);
26,526,953✔
6007
  } else {
6008
    hashKeyBytes = pInfo->colBytes;
121,486,245✔
6009
  }
6010

6011
  SModeItem* pHashItem = (SModeItem*)taosHashGet(pInfo->pHash, data, hashKeyBytes);
148,013,154✔
6012
  if (pHashItem == NULL) {
148,012,142✔
6013
    int32_t   size = sizeof(SModeItem);
107,306,795✔
6014
    SModeItem item = {0};
107,306,795✔
6015

6016
    item.count += 1;
107,306,795✔
6017
    code = saveModeTupleData(pCtx, data, pInfo, &item.dataPos);
107,306,795✔
6018
    if (code != TSDB_CODE_SUCCESS) {
107,306,050!
6019
      return code;
×
6020
    }
6021

6022
    if (pCtx->subsidiaries.num > 0) {
107,306,050✔
6023
      code = saveTupleData(pCtx, rowIndex, pCtx->pSrcBlock, &item.tuplePos);
61,098,308✔
6024
      if (code != TSDB_CODE_SUCCESS) {
61,098,308!
6025
        return code;
×
6026
      }
6027
    }
6028

6029
    code = taosHashPut(pInfo->pHash, data, hashKeyBytes, &item, sizeof(SModeItem));
107,306,050✔
6030
    if (code != TSDB_CODE_SUCCESS) {
107,308,016!
6031
      return code;
×
6032
    }
6033
  } else {
6034
    pHashItem->count += 1;
40,705,347✔
6035
    if (pCtx->subsidiaries.num > 0) {
40,705,347✔
6036
      code = updateTupleData(pCtx, rowIndex, pCtx->pSrcBlock, &pHashItem->tuplePos);
24,958,400✔
6037
      if (code != TSDB_CODE_SUCCESS) {
24,958,400!
6038
        return code;
×
6039
      }
6040
    }
6041
  }
6042

6043
  return code;
148,013,363✔
6044
}
6045

6046
int32_t modeFunction(SqlFunctionCtx* pCtx) {
438,210✔
6047
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
438,210✔
6048
  SModeInfo*           pInfo = GET_ROWCELL_INTERBUF(pResInfo);
438,210✔
6049

6050
  SInputColumnInfoData* pInput = &pCtx->input;
438,210✔
6051

6052
  SColumnInfoData* pInputCol = pInput->pData[0];
438,210✔
6053
  SColumnInfoData* pOutput = (SColumnInfoData*)pCtx->pOutput;
438,210✔
6054

6055
  int32_t numOfElems = 0;
438,210✔
6056
  int32_t startOffset = pCtx->offset;
438,210✔
6057
  for (int32_t i = pInput->startRowIndex; i < pInput->numOfRows + pInput->startRowIndex; ++i) {
148,691,856✔
6058
    if (colDataIsNull_s(pInputCol, i)) {
296,507,246✔
6059
      continue;
240,546✔
6060
    }
6061
    numOfElems++;
148,013,077✔
6062

6063
    char*   data = colDataGetData(pInputCol, i);
148,013,077!
6064
    int32_t code = doModeAdd(pInfo, i, pCtx, data);
148,013,077✔
6065
    if (code != TSDB_CODE_SUCCESS) {
148,013,346✔
6066
      modeFunctionCleanup(pInfo);
246✔
6067
      return code;
×
6068
    }
6069
  }
6070

6071
  if (numOfElems == 0 && pCtx->subsidiaries.num > 0 && !pInfo->nullTupleSaved) {
438,233!
6072
    int32_t code = saveTupleData(pCtx, pInput->startRowIndex, pCtx->pSrcBlock, &pInfo->nullTuplePos);
30✔
6073
    if (code != TSDB_CODE_SUCCESS) {
30!
6074
      modeFunctionCleanup(pInfo);
×
6075
      return code;
×
6076
    }
6077
    pInfo->nullTupleSaved = true;
30✔
6078
  }
6079

6080
  SET_VAL(pResInfo, numOfElems, 1);
438,233✔
6081

6082
  return TSDB_CODE_SUCCESS;
438,233✔
6083
}
6084

6085
int32_t modeFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
53,635✔
6086
  int32_t              code = TSDB_CODE_SUCCESS;
53,635✔
6087
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
53,635✔
6088
  SModeInfo*           pInfo = GET_ROWCELL_INTERBUF(pResInfo);
53,635✔
6089
  int32_t              slotId = pCtx->pExpr->base.resSchema.slotId;
53,635✔
6090
  SColumnInfoData*     pCol = taosArrayGet(pBlock->pDataBlock, slotId);
53,635✔
6091
  int32_t              currentRow = pBlock->info.rows;
53,634✔
6092
  if (NULL == pCol) {
53,634!
6093
    modeFunctionCleanup(pInfo);
×
6094
    return TSDB_CODE_OUT_OF_RANGE;
×
6095
  }
6096

6097
  STuplePos resDataPos, resTuplePos;
6098
  int32_t   maxCount = 0;
53,634✔
6099

6100
  void* pIter = taosHashIterate(pInfo->pHash, NULL);
53,634✔
6101
  while (pIter != NULL) {
107,361,948✔
6102
    SModeItem* pItem = (SModeItem*)pIter;
107,308,312✔
6103
    if (pItem->count >= maxCount) {
107,308,312✔
6104
      maxCount = pItem->count;
96,036,613✔
6105
      resDataPos = pItem->dataPos;
96,036,613✔
6106
      resTuplePos = pItem->tuplePos;
96,036,613✔
6107
    }
6108

6109
    pIter = taosHashIterate(pInfo->pHash, pIter);
107,308,312✔
6110
  }
6111

6112
  if (maxCount != 0) {
53,636✔
6113
    char* pData = NULL;
51,988✔
6114
    code = loadTupleData(pCtx, &resDataPos, &pData);
51,988✔
6115
    if (pData == NULL || TSDB_CODE_SUCCESS != code) {
51,988!
6116
      code = terrno = TSDB_CODE_NOT_FOUND;
×
6117
      qError("Load tuple data failed since %s, groupId:%" PRIu64 ", ts:%" PRId64, terrstr(),
×
6118
             resDataPos.streamTupleKey.groupId, resDataPos.streamTupleKey.ts);
6119
      modeFunctionCleanup(pInfo);
×
6120
      return code;
×
6121
    }
6122

6123
    code = colDataSetVal(pCol, currentRow, pData, false);
51,988✔
6124
    if (TSDB_CODE_SUCCESS != code) {
51,988!
6125
      modeFunctionCleanup(pInfo);
×
6126
      return code;
×
6127
    }
6128
    code = setSelectivityValue(pCtx, pBlock, &resTuplePos, currentRow);
51,988✔
6129
  } else {
6130
    colDataSetNULL(pCol, currentRow);
1,648!
6131
    code = setSelectivityValue(pCtx, pBlock, &pInfo->nullTuplePos, currentRow);
1,648✔
6132
  }
6133

6134
  modeFunctionCleanup(pInfo);
53,637✔
6135

6136
  return code;
53,635✔
6137
}
6138

6139
bool getTwaFuncEnv(struct SFunctionNode* pFunc, SFuncExecEnv* pEnv) {
224,700✔
6140
  pEnv->calcMemSize = sizeof(STwaInfo);
224,700✔
6141
  return true;
224,700✔
6142
}
6143

6144
int32_t twaFunctionSetup(SqlFunctionCtx* pCtx, SResultRowEntryInfo* pResultInfo) {
25,779,246✔
6145
  if (pResultInfo->initialized) {
25,779,246!
6146
    return TSDB_CODE_SUCCESS;
×
6147
  }
6148
  if (TSDB_CODE_SUCCESS != functionSetup(pCtx, pResultInfo)) {
25,779,246!
6149
    return TSDB_CODE_FUNC_SETUP_ERROR;
×
6150
  }
6151

6152
  STwaInfo* pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
25,779,267✔
6153
  pInfo->numOfElems = 0;
25,779,267✔
6154
  pInfo->p.key = INT64_MIN;
25,779,267✔
6155
  pInfo->win = TSWINDOW_INITIALIZER;
25,779,267✔
6156
  return TSDB_CODE_SUCCESS;
25,779,267✔
6157
}
6158

6159
static double twa_get_area(SPoint1 s, SPoint1 e) {
60,869,338✔
6160
  if (e.key == INT64_MAX || s.key == INT64_MIN) {
60,869,338!
6161
    return 0;
×
6162
  }
6163

6164
  if ((s.val >= 0 && e.val >= 0) || (s.val <= 0 && e.val <= 0)) {
60,869,460✔
6165
    return (s.val + e.val) * (e.key - s.key) / 2;
38,274,359✔
6166
  }
6167

6168
  double x = (s.key * e.val - e.key * s.val) / (e.val - s.val);
22,595,101✔
6169
  double val = (s.val * (x - s.key) + e.val * (e.key - x)) / 2;
22,595,101✔
6170
  return val;
22,595,101✔
6171
}
6172

6173
int32_t twaFunction(SqlFunctionCtx* pCtx) {
25,824,778✔
6174
  int32_t               code = TSDB_CODE_SUCCESS;
25,824,778✔
6175
  SInputColumnInfoData* pInput = &pCtx->input;
25,824,778✔
6176
  SColumnInfoData*      pInputCol = pInput->pData[0];
25,824,778✔
6177

6178
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
25,824,778✔
6179
  STwaInfo*            pInfo = GET_ROWCELL_INTERBUF(pResInfo);
25,824,778✔
6180
  SPoint1*             last = &pInfo->p;
25,824,778✔
6181

6182
  if (IS_NULL_TYPE(pInputCol->info.type)) {
25,824,778!
6183
    pInfo->numOfElems = 0;
×
6184
    goto _twa_over;
×
6185
  }
6186

6187
  funcInputUpdate(pCtx);
25,824,778✔
6188
  SFuncInputRow row = {0};
25,825,094✔
6189
  bool          result = false;
25,825,094✔
6190
  if (pCtx->start.key != INT64_MIN && last->key == INT64_MIN) {
25,825,094!
6191
    while (1) {
6192
      code = funcInputGetNextRow(pCtx, &row, &result);
11,450,106✔
6193
      if (TSDB_CODE_SUCCESS != code) {
11,450,210!
6194
        return code;
×
6195
      }
6196
      if (!result) {
11,450,210✔
6197
        break;
2✔
6198
      }
6199
      if (row.isDataNull) {
11,450,208✔
6200
        continue;
2✔
6201
      }
6202

6203
      last->key = row.ts;
11,450,206✔
6204

6205
      GET_TYPED_DATA(last->val, double, pInputCol->info.type, row.pData, typeGetTypeModFromColInfo(&pInputCol->info));
11,450,206!
6206

6207
      pInfo->dOutput += twa_get_area(pCtx->start, *last);
11,450,206✔
6208
      pInfo->win.skey = pCtx->start.key;
11,450,157✔
6209
      pInfo->numOfElems++;
11,450,157✔
6210
      break;
11,450,157✔
6211
    }
6212
  } else if (pInfo->p.key == INT64_MIN) {
14,374,990✔
6213
    while (1) {
6214
      code = funcInputGetNextRow(pCtx, &row, &result);
14,390,788✔
6215
      if (TSDB_CODE_SUCCESS != code) {
14,390,798!
6216
        return code;
×
6217
      }
6218
      if (!result) {
14,390,798✔
6219
        break;
6,783✔
6220
      }
6221
      if (row.isDataNull) {
14,384,015✔
6222
        continue;
59,646✔
6223
      }
6224

6225
      last->key = row.ts;
14,324,369✔
6226

6227
      GET_TYPED_DATA(last->val, double, pInputCol->info.type, row.pData, typeGetTypeModFromColInfo(&pInputCol->info));
14,324,369!
6228

6229
      pInfo->win.skey = last->key;
14,324,278✔
6230
      pInfo->numOfElems++;
14,324,278✔
6231
      break;
14,324,278✔
6232
    }
6233
  }
6234

6235
  SPoint1 st = {0};
25,825,068✔
6236

6237
  // calculate the value of
6238
  while (1) {
6239
    code = funcInputGetNextRow(pCtx, &row, &result);
63,280,763✔
6240
    if (TSDB_CODE_SUCCESS != code) {
63,276,976!
6241
      return code;
×
6242
    }
6243
    if (!result) {
63,276,976✔
6244
      break;
25,825,434✔
6245
    }
6246
    if (row.isDataNull) {
37,451,542✔
6247
      continue;
498✔
6248
    }
6249
    pInfo->numOfElems++;
37,451,044✔
6250
    switch (pInputCol->info.type) {
37,451,044!
6251
      case TSDB_DATA_TYPE_TINYINT: {
25,501,854✔
6252
        INIT_INTP_POINT(st, row.ts, *(int8_t*)row.pData);
25,501,854✔
6253
        break;
25,501,854✔
6254
      }
6255
      case TSDB_DATA_TYPE_SMALLINT: {
1,157,587✔
6256
        INIT_INTP_POINT(st, row.ts, *(int16_t*)row.pData);
1,157,587✔
6257
        break;
1,157,587✔
6258
      }
6259
      case TSDB_DATA_TYPE_INT: {
689,211✔
6260
        INIT_INTP_POINT(st, row.ts, *(int32_t*)row.pData);
689,211✔
6261
        break;
689,211✔
6262
      }
6263
      case TSDB_DATA_TYPE_BIGINT: {
7,049,668✔
6264
        INIT_INTP_POINT(st, row.ts, *(int64_t*)row.pData);
7,049,668✔
6265
        break;
7,049,668✔
6266
      }
6267
      case TSDB_DATA_TYPE_FLOAT: {
326,436✔
6268
        INIT_INTP_POINT(st, row.ts, *(float_t*)row.pData);
326,436✔
6269
        break;
326,436✔
6270
      }
6271
      case TSDB_DATA_TYPE_DOUBLE: {
2,504,194✔
6272
        INIT_INTP_POINT(st, row.ts, *(double*)row.pData);
2,504,194✔
6273
        break;
2,504,194✔
6274
      }
6275
      case TSDB_DATA_TYPE_UTINYINT: {
58,958✔
6276
        INIT_INTP_POINT(st, row.ts, *(uint8_t*)row.pData);
58,958✔
6277
        break;
58,958✔
6278
      }
6279
      case TSDB_DATA_TYPE_USMALLINT: {
59,383✔
6280
        INIT_INTP_POINT(st, row.ts, *(uint16_t*)row.pData);
59,383✔
6281
        break;
59,383✔
6282
      }
6283
      case TSDB_DATA_TYPE_UINT: {
57,851✔
6284
        INIT_INTP_POINT(st, row.ts, *(uint32_t*)row.pData);
57,851✔
6285
        break;
57,851✔
6286
      }
6287
      case TSDB_DATA_TYPE_UBIGINT: {
51,616✔
6288
        INIT_INTP_POINT(st, row.ts, *(uint64_t*)row.pData);
51,616✔
6289
        break;
51,616✔
6290
      }
6291
      default: {
×
6292
        return TSDB_CODE_FUNC_FUNTION_PARA_TYPE;
×
6293
      }
6294
    }
6295
    if (pInfo->p.key == st.key) {
37,456,758!
6296
      return TSDB_CODE_FUNC_DUP_TIMESTAMP;
×
6297
    }
6298

6299
    pInfo->dOutput += twa_get_area(pInfo->p, st);
37,456,758✔
6300
    pInfo->p = st;
37,455,197✔
6301
  }
6302

6303
  // the last interpolated time window value
6304
  if (pCtx->end.key != INT64_MIN) {
25,825,434✔
6305
    pInfo->dOutput += twa_get_area(pInfo->p, pCtx->end);
11,967,857✔
6306
    pInfo->p = pCtx->end;
11,967,822✔
6307
    pInfo->numOfElems += 1;
11,967,822✔
6308
  }
6309

6310
  pInfo->win.ekey = pInfo->p.key;
25,825,399✔
6311

6312
_twa_over:
25,825,399✔
6313
  SET_VAL(pResInfo, 1, 1);
25,825,399✔
6314
  return TSDB_CODE_SUCCESS;
25,825,399✔
6315
}
6316

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

6329
int32_t twaFinalize(struct SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
25,734,996✔
6330
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
25,734,996✔
6331

6332
  STwaInfo* pInfo = (STwaInfo*)GET_ROWCELL_INTERBUF(pResInfo);
25,734,996✔
6333
  if (pInfo->numOfElems == 0) {
25,734,996✔
6334
    pResInfo->numOfRes = 0;
6,667✔
6335
  } else {
6336
    if (pInfo->win.ekey == pInfo->win.skey) {
25,728,329✔
6337
      pInfo->dTwaRes = pInfo->p.val;
11,662,190✔
6338
    } else if (pInfo->win.ekey == INT64_MAX || pInfo->win.skey == INT64_MIN) {  // no data in timewindow
14,066,139!
6339
      pInfo->dTwaRes = 0;
×
6340
    } else {
6341
      pInfo->dTwaRes = pInfo->dOutput / (pInfo->win.ekey - pInfo->win.skey);
14,068,616✔
6342
    }
6343

6344
    pResInfo->numOfRes = 1;
25,728,329✔
6345
  }
6346

6347
  return functionFinalize(pCtx, pBlock);
25,734,996✔
6348
}
6349

6350
int32_t blockDistSetup(SqlFunctionCtx* pCtx, SResultRowEntryInfo* pResultInfo) {
4,874✔
6351
  if (pResultInfo->initialized) {
4,874!
6352
    return TSDB_CODE_SUCCESS;
×
6353
  }
6354
  if (TSDB_CODE_SUCCESS != functionSetup(pCtx, pResultInfo)) {
4,874!
6355
    return TSDB_CODE_FUNC_SETUP_ERROR;
×
6356
  }
6357

6358
  STableBlockDistInfo* pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
4,874✔
6359
  pInfo->minRows = INT32_MAX;
4,874✔
6360
  return TSDB_CODE_SUCCESS;
4,874✔
6361
}
6362

6363
int32_t blockDistFunction(SqlFunctionCtx* pCtx) {
9,746✔
6364
  const int32_t BLOCK_DIST_RESULT_ROWS = 25;
9,746✔
6365

6366
  SInputColumnInfoData* pInput = &pCtx->input;
9,746✔
6367
  SColumnInfoData*      pInputCol = pInput->pData[0];
9,746✔
6368
  SResultRowEntryInfo*  pResInfo = GET_RES_INFO(pCtx);
9,746✔
6369
  STableBlockDistInfo*  pDistInfo = GET_ROWCELL_INTERBUF(pResInfo);
9,746✔
6370

6371
  STableBlockDistInfo p1 = {0};
9,746✔
6372
  if (tDeserializeBlockDistInfo(varDataVal(pInputCol->pData), varDataLen(pInputCol->pData), &p1) < 0) {
9,746!
6373
    qError("failed to deserialize block dist info");
×
6374
    return TSDB_CODE_FAILED;
×
6375
  }
6376

6377
  pDistInfo->numOfBlocks += p1.numOfBlocks;
9,746✔
6378
  pDistInfo->numOfTables += p1.numOfTables;
9,746✔
6379
  pDistInfo->numOfInmemRows += p1.numOfInmemRows;
9,746✔
6380
  pDistInfo->numOfSttRows += p1.numOfSttRows;
9,746✔
6381
  pDistInfo->totalSize += p1.totalSize;
9,746✔
6382
  pDistInfo->totalRows += p1.totalRows;
9,746✔
6383
  pDistInfo->numOfFiles += p1.numOfFiles;
9,746✔
6384

6385
  pDistInfo->defMinRows = p1.defMinRows;
9,746✔
6386
  pDistInfo->defMaxRows = p1.defMaxRows;
9,746✔
6387
  pDistInfo->rowSize = p1.rowSize;
9,746✔
6388

6389
  if (pDistInfo->minRows > p1.minRows) {
9,746✔
6390
    pDistInfo->minRows = p1.minRows;
5✔
6391
  }
6392
  if (pDistInfo->maxRows < p1.maxRows) {
9,746✔
6393
    pDistInfo->maxRows = p1.maxRows;
5✔
6394
  }
6395
  pDistInfo->numOfVgroups += (p1.numOfTables != 0 ? 1 : 0);
9,746✔
6396
  for (int32_t i = 0; i < tListLen(pDistInfo->blockRowsHisto); ++i) {
204,666✔
6397
    pDistInfo->blockRowsHisto[i] += p1.blockRowsHisto[i];
194,920✔
6398
  }
6399

6400
  pResInfo->numOfRes = BLOCK_DIST_RESULT_ROWS;  // default output rows
9,746✔
6401
  return TSDB_CODE_SUCCESS;
9,746✔
6402
}
6403

6404
int32_t tSerializeBlockDistInfo(void* buf, int32_t bufLen, const STableBlockDistInfo* pInfo) {
19,430✔
6405
  SEncoder encoder = {0};
19,430✔
6406
  int32_t  code = 0;
19,430✔
6407
  int32_t  lino;
6408
  int32_t  tlen;
6409
  tEncoderInit(&encoder, buf, bufLen);
19,430✔
6410

6411
  TAOS_CHECK_EXIT(tStartEncode(&encoder));
19,448!
6412
  TAOS_CHECK_EXIT(tEncodeU32(&encoder, pInfo->rowSize));
38,894!
6413

6414
  TAOS_CHECK_EXIT(tEncodeU16(&encoder, pInfo->numOfFiles));
38,894!
6415
  TAOS_CHECK_EXIT(tEncodeU32(&encoder, pInfo->numOfBlocks));
38,894!
6416
  TAOS_CHECK_EXIT(tEncodeU32(&encoder, pInfo->numOfTables));
38,894!
6417

6418
  TAOS_CHECK_EXIT(tEncodeU64(&encoder, pInfo->totalSize));
38,894!
6419
  TAOS_CHECK_EXIT(tEncodeU64(&encoder, pInfo->totalRows));
38,894!
6420
  TAOS_CHECK_EXIT(tEncodeI32(&encoder, pInfo->maxRows));
38,894!
6421
  TAOS_CHECK_EXIT(tEncodeI32(&encoder, pInfo->minRows));
38,894!
6422
  TAOS_CHECK_EXIT(tEncodeI32(&encoder, pInfo->defMaxRows));
38,894!
6423
  TAOS_CHECK_EXIT(tEncodeI32(&encoder, pInfo->defMinRows));
38,894!
6424
  TAOS_CHECK_EXIT(tEncodeU32(&encoder, pInfo->numOfInmemRows));
38,894!
6425
  TAOS_CHECK_EXIT(tEncodeU32(&encoder, pInfo->numOfSttRows));
38,894!
6426
  TAOS_CHECK_EXIT(tEncodeU32(&encoder, pInfo->numOfVgroups));
38,894!
6427

6428
  for (int32_t i = 0; i < tListLen(pInfo->blockRowsHisto); ++i) {
407,501✔
6429
    TAOS_CHECK_EXIT(tEncodeI32(&encoder, pInfo->blockRowsHisto[i]));
776,108!
6430
  }
6431

6432
  tEndEncode(&encoder);
19,447✔
6433

6434
_exit:
19,445✔
6435
  if (code) {
19,445!
6436
    tlen = code;
×
6437
  } else {
6438
    tlen = encoder.pos;
19,445✔
6439
  }
6440
  tEncoderClear(&encoder);
19,445✔
6441
  return tlen;
19,440✔
6442
}
6443

6444
int32_t tDeserializeBlockDistInfo(void* buf, int32_t bufLen, STableBlockDistInfo* pInfo) {
9,746✔
6445
  SDecoder decoder = {0};
9,746✔
6446
  int32_t  code = 0;
9,746✔
6447
  int32_t  lino;
6448
  tDecoderInit(&decoder, buf, bufLen);
9,746✔
6449

6450
  TAOS_CHECK_EXIT(tStartDecode(&decoder));
9,746!
6451
  TAOS_CHECK_EXIT(tDecodeU32(&decoder, &pInfo->rowSize));
19,492!
6452

6453
  TAOS_CHECK_EXIT(tDecodeU16(&decoder, &pInfo->numOfFiles));
19,492!
6454
  TAOS_CHECK_EXIT(tDecodeU32(&decoder, &pInfo->numOfBlocks));
19,492!
6455
  TAOS_CHECK_EXIT(tDecodeU32(&decoder, &pInfo->numOfTables));
19,492!
6456

6457
  TAOS_CHECK_EXIT(tDecodeU64(&decoder, &pInfo->totalSize));
19,492!
6458
  TAOS_CHECK_EXIT(tDecodeU64(&decoder, &pInfo->totalRows));
19,492!
6459
  TAOS_CHECK_EXIT(tDecodeI32(&decoder, &pInfo->maxRows));
19,492!
6460
  TAOS_CHECK_EXIT(tDecodeI32(&decoder, &pInfo->minRows));
19,492!
6461
  TAOS_CHECK_EXIT(tDecodeI32(&decoder, &pInfo->defMaxRows));
19,492!
6462
  TAOS_CHECK_EXIT(tDecodeI32(&decoder, &pInfo->defMinRows));
19,492!
6463
  TAOS_CHECK_EXIT(tDecodeU32(&decoder, &pInfo->numOfInmemRows));
19,492!
6464
  TAOS_CHECK_EXIT(tDecodeU32(&decoder, &pInfo->numOfSttRows));
19,492!
6465
  TAOS_CHECK_EXIT(tDecodeU32(&decoder, &pInfo->numOfVgroups));
19,492!
6466

6467
  for (int32_t i = 0; i < tListLen(pInfo->blockRowsHisto); ++i) {
204,666✔
6468
    TAOS_CHECK_EXIT(tDecodeI32(&decoder, &pInfo->blockRowsHisto[i]));
389,840!
6469
  }
6470

6471
_exit:
9,746✔
6472
  tDecoderClear(&decoder);
9,746✔
6473
  return code;
9,746✔
6474
}
6475

6476
int32_t blockDistFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
4,874✔
6477
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
4,874✔
6478
  STableBlockDistInfo* pData = GET_ROWCELL_INTERBUF(pResInfo);
4,874✔
6479

6480
  SColumnInfoData* pColInfo = taosArrayGet(pBlock->pDataBlock, 0);
4,874✔
6481
  if (NULL == pColInfo) {
4,874!
6482
    return TSDB_CODE_OUT_OF_RANGE;
×
6483
  }
6484

6485
  if (pData->totalRows == 0) {
4,874✔
6486
    pData->minRows = 0;
4,869✔
6487
  }
6488

6489
  int32_t row = 0;
4,874✔
6490
  char    st[256] = {0};
4,874✔
6491
  double  averageSize = 0;
4,874✔
6492
  if (pData->numOfBlocks != 0) {
4,874✔
6493
    averageSize = ((double)pData->totalSize) / pData->numOfBlocks;
5✔
6494
  }
6495
  uint64_t totalRawSize = pData->totalRows * pData->rowSize;
4,874✔
6496
  double   compRatio = 0;
4,874✔
6497
  if (totalRawSize != 0) {
4,874✔
6498
    compRatio = pData->totalSize * 100 / (double)totalRawSize;
5✔
6499
  }
6500

6501
  int32_t len = tsnprintf(varDataVal(st), sizeof(st) - VARSTR_HEADER_SIZE,
9,748✔
6502
                          "Total_Blocks=[%d] Total_Size=[%.2f KiB] Average_size=[%.2f KiB] Compression_Ratio=[%.2f %c]",
6503
                          pData->numOfBlocks, pData->totalSize / 1024.0, averageSize / 1024.0, compRatio, '%');
4,874✔
6504

6505
  varDataSetLen(st, len);
4,874✔
6506
  int32_t code = colDataSetVal(pColInfo, row++, st, false);
4,874✔
6507
  if (TSDB_CODE_SUCCESS != code) {
4,874!
6508
    return code;
×
6509
  }
6510

6511
  int64_t avgRows = 0;
4,874✔
6512
  if (pData->numOfBlocks > 0) {
4,874✔
6513
    avgRows = pData->totalRows / pData->numOfBlocks;
5✔
6514
  }
6515

6516
  len = tsnprintf(varDataVal(st), sizeof(st) - VARSTR_HEADER_SIZE,
4,874✔
6517
                  "Block_Rows=[%" PRId64 "] MinRows=[%d] MaxRows=[%d] AvgRows=[%" PRId64 "]", pData->totalRows,
6518
                  pData->minRows, pData->maxRows, avgRows);
6519
  varDataSetLen(st, len);
4,874✔
6520
  code = colDataSetVal(pColInfo, row++, st, false);
4,874✔
6521
  if (TSDB_CODE_SUCCESS != code) {
4,874!
6522
    return code;
×
6523
  }
6524

6525
  len = tsnprintf(varDataVal(st), sizeof(st) - VARSTR_HEADER_SIZE, "Inmem_Rows=[%u] Stt_Rows=[%u] ",
4,874✔
6526
                  pData->numOfInmemRows, pData->numOfSttRows);
6527
  varDataSetLen(st, len);
4,874✔
6528
  code = colDataSetVal(pColInfo, row++, st, false);
4,874✔
6529
  if (TSDB_CODE_SUCCESS != code) {
4,874!
6530
    return code;
×
6531
  }
6532

6533
  len = tsnprintf(varDataVal(st), sizeof(st) - VARSTR_HEADER_SIZE,
9,748✔
6534
                  "Total_Tables=[%d] Total_Filesets=[%d] Total_Vgroups=[%d]", pData->numOfTables, pData->numOfFiles,
4,874✔
6535
                  pData->numOfVgroups);
6536

6537
  varDataSetLen(st, len);
4,874✔
6538
  code = colDataSetVal(pColInfo, row++, st, false);
4,874✔
6539
  if (TSDB_CODE_SUCCESS != code) {
4,874!
6540
    return code;
×
6541
  }
6542

6543
  len = tsnprintf(varDataVal(st), sizeof(st) - VARSTR_HEADER_SIZE,
4,874✔
6544
                  "--------------------------------------------------------------------------------");
6545
  varDataSetLen(st, len);
4,874✔
6546
  code = colDataSetVal(pColInfo, row++, st, false);
4,874✔
6547
  if (TSDB_CODE_SUCCESS != code) {
4,874!
6548
    return code;
×
6549
  }
6550

6551
  int32_t maxVal = 0;
4,874✔
6552
  int32_t minVal = INT32_MAX;
4,874✔
6553
  for (int32_t i = 0; i < tListLen(pData->blockRowsHisto); ++i) {
102,354✔
6554
    if (maxVal < pData->blockRowsHisto[i]) {
97,480✔
6555
      maxVal = pData->blockRowsHisto[i];
10✔
6556
    }
6557

6558
    if (minVal > pData->blockRowsHisto[i]) {
97,480✔
6559
      minVal = pData->blockRowsHisto[i];
4,875✔
6560
    }
6561
  }
6562

6563
  // maximum number of step is 80
6564
  double factor = pData->numOfBlocks / 80.0;
4,874✔
6565

6566
  int32_t numOfBuckets = sizeof(pData->blockRowsHisto) / sizeof(pData->blockRowsHisto[0]);
4,874✔
6567
  int32_t bucketRange = ceil(((double)(pData->defMaxRows - pData->defMinRows)) / numOfBuckets);
4,874✔
6568

6569
  for (int32_t i = 0; i < tListLen(pData->blockRowsHisto); ++i) {
102,354✔
6570
    len =
97,480✔
6571
        tsnprintf(varDataVal(st), sizeof(st) - VARSTR_HEADER_SIZE, "%04d |", pData->defMinRows + bucketRange * (i + 1));
97,480✔
6572

6573
    int32_t num = 0;
97,480✔
6574
    if (pData->blockRowsHisto[i] > 0) {
97,480✔
6575
      num = (pData->blockRowsHisto[i]) / factor;
12✔
6576
    }
6577

6578
    for (int32_t j = 0; j < num; ++j) {
97,876✔
6579
      int32_t x = tsnprintf(varDataVal(st) + len, sizeof(st) - VARSTR_HEADER_SIZE - len, "%c", '|');
396✔
6580
      len += x;
396✔
6581
    }
6582

6583
    if (pData->blockRowsHisto[i] > 0) {
97,480✔
6584
      double v = pData->blockRowsHisto[i] * 100.0 / pData->numOfBlocks;
12✔
6585
      len += tsnprintf(varDataVal(st) + len, sizeof(st) - VARSTR_HEADER_SIZE - len, "  %d (%.2f%c)",
12✔
6586
                       pData->blockRowsHisto[i], v, '%');
6587
    }
6588

6589
    varDataSetLen(st, len);
97,480✔
6590
    code = colDataSetVal(pColInfo, row++, st, false);
97,480✔
6591
    if (TSDB_CODE_SUCCESS != code) {
97,480!
6592
      return code;
×
6593
    }
6594
  }
6595

6596
  return TSDB_CODE_SUCCESS;
4,874✔
6597
}
6598
int32_t blockDBUsageSetup(SqlFunctionCtx* pCtx, SResultRowEntryInfo* pResultInfo) {
4✔
6599
  if (pResultInfo->initialized) {
4!
6600
    return TSDB_CODE_SUCCESS;
×
6601
  }
6602
  if (TSDB_CODE_SUCCESS != functionSetup(pCtx, pResultInfo)) {
4!
6603
    return TSDB_CODE_FUNC_SETUP_ERROR;
×
6604
  }
6605

6606
  SDBBlockUsageInfo* pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
4✔
6607
  return TSDB_CODE_SUCCESS;
4✔
6608
}
6609
int32_t blockDBUsageFunction(SqlFunctionCtx* pCtx) {
8✔
6610
  const int32_t BLOCK_DISK_USAGE_RESULT_ROWS = 2;
8✔
6611

6612
  SInputColumnInfoData* pInput = &pCtx->input;
8✔
6613
  SColumnInfoData*      pInputCol = pInput->pData[0];
8✔
6614
  SResultRowEntryInfo*  pResInfo = GET_RES_INFO(pCtx);
8✔
6615
  SDBBlockUsageInfo*    pDistInfo = GET_ROWCELL_INTERBUF(pResInfo);
8✔
6616

6617
  SDBBlockUsageInfo p1 = {0};
8✔
6618
  if (tDeserializeBlockDbUsage(varDataVal(pInputCol->pData), varDataLen(pInputCol->pData), &p1) < 0) {
8!
6619
    qError("failed to deserialize block dist info");
×
6620
    return TSDB_CODE_FAILED;
×
6621
  }
6622

6623
  pDistInfo->dataInDiskSize += p1.dataInDiskSize;
8✔
6624
  pDistInfo->walInDiskSize += p1.walInDiskSize;
8✔
6625
  pDistInfo->rawDataSize += p1.rawDataSize;
8✔
6626
  pResInfo->numOfRes = BLOCK_DISK_USAGE_RESULT_ROWS;  // default output rows
8✔
6627
  return TSDB_CODE_SUCCESS;
8✔
6628
}
6629

6630
int32_t tSerializeBlockDbUsage(void* buf, int32_t bufLen, const SDBBlockUsageInfo* pInfo) {
16✔
6631
  SEncoder encoder = {0};
16✔
6632
  int32_t  code = 0;
16✔
6633
  int32_t  lino;
6634
  int32_t  tlen;
6635
  tEncoderInit(&encoder, buf, bufLen);
16✔
6636

6637
  TAOS_CHECK_EXIT(tStartEncode(&encoder));
16!
6638

6639
  TAOS_CHECK_EXIT(tEncodeU64(&encoder, pInfo->dataInDiskSize));
32!
6640
  TAOS_CHECK_EXIT(tEncodeU64(&encoder, pInfo->walInDiskSize));
32!
6641
  TAOS_CHECK_EXIT(tEncodeU64(&encoder, pInfo->rawDataSize));
32!
6642

6643
  tEndEncode(&encoder);
16✔
6644

6645
_exit:
16✔
6646
  if (code) {
16!
6647
    tlen = code;
×
6648
  } else {
6649
    tlen = encoder.pos;
16✔
6650
  }
6651
  tEncoderClear(&encoder);
16✔
6652
  return tlen;
16✔
6653
}
6654
int32_t tDeserializeBlockDbUsage(void* buf, int32_t bufLen, SDBBlockUsageInfo* pInfo) {
8✔
6655
  SDecoder decoder = {0};
8✔
6656
  int32_t  code = 0;
8✔
6657
  int32_t  lino;
6658
  tDecoderInit(&decoder, buf, bufLen);
8✔
6659

6660
  TAOS_CHECK_EXIT(tStartDecode(&decoder));
8!
6661
  TAOS_CHECK_EXIT(tDecodeU64(&decoder, &pInfo->dataInDiskSize));
16!
6662
  TAOS_CHECK_EXIT(tDecodeU64(&decoder, &pInfo->walInDiskSize));
16!
6663
  TAOS_CHECK_EXIT(tDecodeU64(&decoder, &pInfo->rawDataSize));
16!
6664

6665
_exit:
8✔
6666
  tDecoderClear(&decoder);
8✔
6667
  return code;
8✔
6668
}
6669
int32_t blockDBUsageFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
4✔
6670
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
4✔
6671
  SDBBlockUsageInfo*   pData = GET_ROWCELL_INTERBUF(pResInfo);
4✔
6672

6673
  SColumnInfoData* pColInfo = taosArrayGet(pBlock->pDataBlock, 0);
4✔
6674
  if (NULL == pColInfo) {
4!
6675
    return TSDB_CODE_OUT_OF_RANGE;
×
6676
  }
6677
  int32_t len = 0;
4✔
6678
  int32_t row = 0;
4✔
6679
  char    st[256] = {0};
4✔
6680

6681
  uint64_t totalDiskSize = pData->dataInDiskSize;
4✔
6682
  uint64_t rawDataSize = pData->rawDataSize;
4✔
6683
  double   compressRatio = 0;
4✔
6684
  if (rawDataSize != 0) {
4✔
6685
    compressRatio = totalDiskSize * 100 / (double)rawDataSize;
3✔
6686
    len = tsnprintf(varDataVal(st), sizeof(st) - VARSTR_HEADER_SIZE, "Compress_ratio=[%.2f%]", compressRatio);
3✔
6687
  } else {
6688
    len = tsnprintf(varDataVal(st), sizeof(st) - VARSTR_HEADER_SIZE, "Compress_ratio=[NULL]");
1✔
6689
  }
6690

6691
  varDataSetLen(st, len);
4✔
6692
  int32_t code = colDataSetVal(pColInfo, row++, st, false);
4✔
6693
  if (TSDB_CODE_SUCCESS != code) {
4!
6694
    return code;
×
6695
  }
6696

6697
  len =
4✔
6698
      tsnprintf(varDataVal(st), sizeof(st) - VARSTR_HEADER_SIZE, "Disk_occupied=[%" PRId64 "k]", pData->dataInDiskSize);
4✔
6699
  varDataSetLen(st, len);
4✔
6700
  code = colDataSetVal(pColInfo, row++, st, false);
4✔
6701
  if (TSDB_CODE_SUCCESS != code) {
4!
6702
    return code;
×
6703
  }
6704
  return code;
4✔
6705
}
6706

6707
bool getDerivativeFuncEnv(struct SFunctionNode* pFunc, SFuncExecEnv* pEnv) {
90,076✔
6708
  pEnv->calcMemSize = sizeof(SDerivInfo);
90,076✔
6709
  return true;
90,076✔
6710
}
6711

6712
int32_t derivativeFuncSetup(SqlFunctionCtx* pCtx, SResultRowEntryInfo* pResInfo) {
203,144✔
6713
  if (pResInfo->initialized) {
203,144✔
6714
    return TSDB_CODE_SUCCESS;
112,985✔
6715
  }
6716
  if (TSDB_CODE_SUCCESS != functionSetup(pCtx, pResInfo)) {
90,159!
6717
    return TSDB_CODE_FUNC_SETUP_ERROR;
×
6718
  }
6719

6720
  SDerivInfo* pDerivInfo = GET_ROWCELL_INTERBUF(pResInfo);
90,159✔
6721

6722
  pDerivInfo->ignoreNegative = pCtx->param[2].param.i;
90,159✔
6723
  pDerivInfo->prevTs = -1;
90,159✔
6724
  pDerivInfo->tsWindow = pCtx->param[1].param.i;
90,159✔
6725
  pDerivInfo->valueSet = false;
90,159✔
6726
  return TSDB_CODE_SUCCESS;
90,159✔
6727
}
6728

6729
int32_t derivativeFunction(SqlFunctionCtx* pCtx) {
113,068✔
6730
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
113,068✔
6731
  SDerivInfo*          pDerivInfo = GET_ROWCELL_INTERBUF(pResInfo);
113,068✔
6732

6733
  SInputColumnInfoData* pInput = &pCtx->input;
113,068✔
6734
  SColumnInfoData*      pInputCol = pInput->pData[0];
113,068✔
6735

6736
  int32_t          numOfElems = 0;
113,068✔
6737
  SColumnInfoData* pOutput = (SColumnInfoData*)pCtx->pOutput;
113,068✔
6738
  SColumnInfoData* pTsOutput = pCtx->pTsOutput;
113,068✔
6739
  int32_t          code = TSDB_CODE_SUCCESS;
113,068✔
6740

6741
  funcInputUpdate(pCtx);
113,068✔
6742

6743
  double v = 0;
113,068✔
6744
  if (pCtx->order == TSDB_ORDER_ASC) {
113,068✔
6745
    SFuncInputRow row = {0};
103,017✔
6746
    bool          result = false;
103,017✔
6747
    while (1) {
8,814,778✔
6748
      code = funcInputGetNextRow(pCtx, &row, &result);
8,917,795✔
6749
      if (TSDB_CODE_SUCCESS != code) {
8,917,795!
6750
        return code;
×
6751
      }
6752
      if (!result) {
8,917,795✔
6753
        break;
103,017✔
6754
      }
6755
      if (row.isDataNull) {
8,814,778✔
6756
        continue;
18,911✔
6757
      }
6758

6759
      char* d = row.pData;
8,795,867✔
6760
      GET_TYPED_DATA(v, double, pInputCol->info.type, d, typeGetTypeModFromColInfo(&pInputCol->info));
8,795,867!
6761

6762
      int32_t pos = pCtx->offset + numOfElems;
8,795,867✔
6763
      if (!pDerivInfo->valueSet) {  // initial value is not set yet
8,795,867✔
6764
        pDerivInfo->valueSet = true;
79,920✔
6765
      } else {
6766
        if (row.ts == pDerivInfo->prevTs) {
8,715,947!
6767
          return TSDB_CODE_FUNC_DUP_TIMESTAMP;
×
6768
        }
6769
        double r = ((v - pDerivInfo->prevValue) * pDerivInfo->tsWindow) / (row.ts - pDerivInfo->prevTs);
8,715,947✔
6770
        if (pDerivInfo->ignoreNegative && r < 0) {
8,715,947✔
6771
        } else {
6772
          if (isinf(r) || isnan(r)) {
5,387,250!
6773
            colDataSetNULL(pOutput, pos);
×
6774
          } else {
6775
            code = colDataSetVal(pOutput, pos, (const char*)&r, false);
5,387,250✔
6776
            if (code != TSDB_CODE_SUCCESS) {
5,387,250!
6777
              return code;
×
6778
            }
6779
          }
6780

6781
          if (pTsOutput != NULL) {
5,387,250!
6782
            colDataSetInt64(pTsOutput, pos, &row.ts);
×
6783
          }
6784

6785
          // handle selectivity
6786
          if (pCtx->subsidiaries.num > 0) {
5,387,250✔
6787
            code = appendSelectivityCols(pCtx, row.block, row.rowIndex, pos);
3,778,570✔
6788
            if (code != TSDB_CODE_SUCCESS) {
3,778,570!
6789
              return code;
×
6790
            }
6791
          }
6792

6793
          numOfElems++;
5,387,250✔
6794
        }
6795
      }
6796

6797
      pDerivInfo->prevValue = v;
8,795,867✔
6798
      pDerivInfo->prevTs = row.ts;
8,795,867✔
6799
    }
6800
  } else {
6801
    SFuncInputRow row = {0};
10,051✔
6802
    bool          result = false;
10,051✔
6803
    while (1) {
1,002,352✔
6804
      code = funcInputGetNextRow(pCtx, &row, &result);
1,012,403✔
6805
      if (TSDB_CODE_SUCCESS != code) {
1,012,403!
6806
        return code;
×
6807
      }
6808
      if (!result) {
1,012,403✔
6809
        break;
10,051✔
6810
      }
6811
      if (row.isDataNull) {
1,002,352✔
6812
        continue;
54✔
6813
      }
6814

6815
      char* d = row.pData;
1,002,298✔
6816
      GET_TYPED_DATA(v, double, pInputCol->info.type, d, typeGetTypeModFromColInfo(&pInputCol->info));
1,002,298!
6817

6818
      int32_t pos = pCtx->offset + numOfElems;
1,002,298✔
6819
      if (!pDerivInfo->valueSet) {  // initial value is not set yet
1,002,298✔
6820
        pDerivInfo->valueSet = true;
10,033✔
6821
      } else {
6822
        if (row.ts == pDerivInfo->prevTs) {
992,265!
6823
          return TSDB_CODE_FUNC_DUP_TIMESTAMP;
×
6824
        }
6825
        double r = ((pDerivInfo->prevValue - v) * pDerivInfo->tsWindow) / (pDerivInfo->prevTs - row.ts);
992,265✔
6826
        if (pDerivInfo->ignoreNegative && r < 0) {
992,265✔
6827
        } else {
6828
          if (isinf(r) || isnan(r)) {
690,967!
6829
            colDataSetNULL(pOutput, pos);
×
6830
          } else {
6831
            code = colDataSetVal(pOutput, pos, (const char*)&r, false);
690,967✔
6832
            if (code != TSDB_CODE_SUCCESS) {
690,967!
6833
              return code;
×
6834
            }
6835
          }
6836

6837
          if (pTsOutput != NULL) {
690,967!
6838
            colDataSetInt64(pTsOutput, pos, &pDerivInfo->prevTs);
×
6839
          }
6840

6841
          // handle selectivity
6842
          if (pCtx->subsidiaries.num > 0) {
690,967✔
6843
            code = appendSelectivityCols(pCtx, row.block, row.rowIndex, pos);
218,242✔
6844
            if (code != TSDB_CODE_SUCCESS) {
218,242!
6845
              return code;
×
6846
            }
6847
          }
6848
          numOfElems++;
690,967✔
6849
        }
6850
      }
6851

6852
      pDerivInfo->prevValue = v;
1,002,298✔
6853
      pDerivInfo->prevTs = row.ts;
1,002,298✔
6854
    }
6855
  }
6856

6857
  pResInfo->numOfRes = numOfElems;
113,068✔
6858

6859
  return TSDB_CODE_SUCCESS;
113,068✔
6860
}
6861

6862
int32_t getIrateInfoSize(int32_t pkBytes) { return (int32_t)sizeof(SRateInfo) + 2 * pkBytes; }
6,782,218✔
6863

6864
bool getIrateFuncEnv(struct SFunctionNode* pFunc, SFuncExecEnv* pEnv) {
366,336✔
6865
  int32_t pkBytes = (pFunc->hasPk) ? pFunc->pkBytes : 0;
366,336✔
6866
  pEnv->calcMemSize = getIrateInfoSize(pkBytes);
366,336✔
6867
  return true;
366,966✔
6868
}
6869

6870
int32_t irateFuncSetup(SqlFunctionCtx* pCtx, SResultRowEntryInfo* pResInfo) {
36,041,572✔
6871
  if (pResInfo->initialized) {
36,041,572!
6872
    return TSDB_CODE_SUCCESS;
×
6873
  }
6874
  if (TSDB_CODE_SUCCESS != functionSetup(pCtx, pResInfo)) {
36,041,572!
6875
    return TSDB_CODE_FUNC_SETUP_ERROR;
×
6876
  }
6877

6878
  SRateInfo* pInfo = GET_ROWCELL_INTERBUF(pResInfo);
36,041,531✔
6879

6880
  pInfo->firstKey = INT64_MIN;
36,041,531✔
6881
  pInfo->lastKey = INT64_MIN;
36,041,531✔
6882
  pInfo->firstValue = (double)INT64_MIN;
36,041,531✔
6883
  pInfo->lastValue = (double)INT64_MIN;
36,041,531✔
6884

6885
  pInfo->hasResult = 0;
36,041,531✔
6886
  return TSDB_CODE_SUCCESS;
36,041,531✔
6887
}
6888

6889
static void doSaveRateInfo(SRateInfo* pRateInfo, bool isFirst, int64_t ts, char* pk, double v) {
157,971,441✔
6890
  if (isFirst) {
157,971,441✔
6891
    pRateInfo->firstValue = v;
64,180,209✔
6892
    pRateInfo->firstKey = ts;
64,180,209✔
6893
    if (pRateInfo->firstPk) {
64,180,209✔
6894
      int32_t pkBytes;
6895
      if (IS_VAR_DATA_TYPE(pRateInfo->pkType)) {
35!
6896
        pkBytes = calcStrBytesByType(pRateInfo->pkType, pk);
8✔
6897
      } else {
6898
        pkBytes = pRateInfo->pkBytes;
27✔
6899
      }
6900
      (void)memcpy(pRateInfo->firstPk, pk, pkBytes);
35✔
6901
    }
6902
  } else {
6903
    pRateInfo->lastValue = v;
93,791,232✔
6904
    pRateInfo->lastKey = ts;
93,791,232✔
6905
    if (pRateInfo->lastPk) {
93,791,232✔
6906
      int32_t pkBytes;
6907
      if (IS_VAR_DATA_TYPE(pRateInfo->pkType)) {
52!
6908
        pkBytes = calcStrBytesByType(pRateInfo->pkType, pk);
12✔
6909
      } else {
6910
        pkBytes = pRateInfo->pkBytes;
40✔
6911
      }
6912
      (void)memcpy(pRateInfo->lastPk, pk, pkBytes);
52✔
6913
    }
6914
  }
6915
}
157,971,441✔
6916

6917
static void initializeRateInfo(SqlFunctionCtx* pCtx, SRateInfo* pRateInfo, bool isMerge) {
42,533,715✔
6918
  if (pCtx->hasPrimaryKey) {
42,533,715✔
6919
    if (!isMerge) {
19✔
6920
      pRateInfo->pkType = pCtx->input.pPrimaryKey->info.type;
17✔
6921
      pRateInfo->pkBytes = pCtx->input.pPrimaryKey->info.bytes;
17✔
6922
      pRateInfo->firstPk = pRateInfo->pkData;
17✔
6923
      pRateInfo->lastPk = pRateInfo->pkData + pRateInfo->pkBytes;
17✔
6924
    } else {
6925
      pRateInfo->firstPk = pRateInfo->pkData;
2✔
6926
      pRateInfo->lastPk = pRateInfo->pkData + pRateInfo->pkBytes;
2✔
6927
    }
6928
  } else {
6929
    pRateInfo->firstPk = NULL;
42,533,696✔
6930
    pRateInfo->lastPk = NULL;
42,533,696✔
6931
  }
6932
}
42,533,715✔
6933

6934
int32_t irateFunction(SqlFunctionCtx* pCtx) {
29,705,342✔
6935
  int32_t              code = TSDB_CODE_SUCCESS;
29,705,342✔
6936
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
29,705,342✔
6937
  SRateInfo*           pRateInfo = GET_ROWCELL_INTERBUF(pResInfo);
29,705,342✔
6938

6939
  SInputColumnInfoData* pInput = &pCtx->input;
29,705,342✔
6940
  SColumnInfoData*      pInputCol = pInput->pData[0];
29,705,342✔
6941

6942
  SColumnInfoData* pOutput = (SColumnInfoData*)pCtx->pOutput;
29,705,342✔
6943

6944
  funcInputUpdate(pCtx);
29,705,342✔
6945

6946
  initializeRateInfo(pCtx, pRateInfo, false);
29,705,602✔
6947

6948
  int32_t       numOfElems = 0;
29,706,091✔
6949
  int32_t       type = pInputCol->info.type;
29,706,091✔
6950
  SFuncInputRow row = {0};
29,706,091✔
6951
  bool          result = false;
29,706,091✔
6952
  while (1) {
88,137,751✔
6953
    code = funcInputGetNextRow(pCtx, &row, &result);
117,843,842✔
6954
    if (TSDB_CODE_SUCCESS != code) {
117,840,772!
6955
      return code;
×
6956
    }
6957
    if (!result) {
117,840,772✔
6958
      break;
29,706,061✔
6959
    }
6960
    if (row.isDataNull) {
88,134,711✔
6961
      continue;
64,928✔
6962
    }
6963

6964
    char*  data = row.pData;
88,069,783✔
6965
    double v = 0;
88,069,783✔
6966
    GET_TYPED_DATA(v, double, type, data, typeGetTypeModFromColInfo(&pInputCol->info));
88,069,783!
6967

6968
    if (INT64_MIN == pRateInfo->lastKey) {
88,078,016✔
6969
      doSaveRateInfo(pRateInfo, false, row.ts, row.pPk, v);
29,621,288✔
6970
      pRateInfo->hasResult = 1;
29,621,078✔
6971
      continue;
29,621,078✔
6972
    }
6973

6974
    if (row.ts > pRateInfo->lastKey) {
58,456,728✔
6975
      if ((INT64_MIN == pRateInfo->firstKey) || pRateInfo->lastKey > pRateInfo->firstKey) {
57,764,586!
6976
        doSaveRateInfo(pRateInfo, true, pRateInfo->lastKey, pRateInfo->lastPk, pRateInfo->lastValue);
57,764,591✔
6977
      }
6978
      doSaveRateInfo(pRateInfo, false, row.ts, row.pPk, v);
57,764,303✔
6979
      continue;
57,763,655✔
6980
    } else if (row.ts == pRateInfo->lastKey) {
692,142!
6981
      return TSDB_CODE_FUNC_DUP_TIMESTAMP;
×
6982
    }
6983

6984
    if ((INT64_MIN == pRateInfo->firstKey) || row.ts > pRateInfo->firstKey) {
692,142!
6985
      doSaveRateInfo(pRateInfo, true, row.ts, row.pPk, v);
1,295✔
6986
    } else if (row.ts == pRateInfo->firstKey) {
690,847!
6987
      return TSDB_CODE_FUNC_DUP_TIMESTAMP;
×
6988
    }
6989
  }
6990

6991
  numOfElems++;
29,706,061✔
6992

6993
  SET_VAL(pResInfo, numOfElems, 1);
29,706,061!
6994
  return TSDB_CODE_SUCCESS;
29,706,061✔
6995
}
6996

6997
static double doCalcRate(const SRateInfo* pRateInfo, double tickPerSec) {
29,599,839✔
6998
  if ((INT64_MIN == pRateInfo->lastKey) || (INT64_MIN == pRateInfo->firstKey) ||
29,599,839✔
6999
      (pRateInfo->firstKey >= pRateInfo->lastKey)) {
8,798,896!
7000
    return 0.0;
20,800,941✔
7001
  }
7002

7003
  double diff = 0;
8,798,898✔
7004
  // If the previous value of the last is greater than the last value, only keep the last point instead of the delta
7005
  // value between two values.
7006
  diff = pRateInfo->lastValue;
8,798,898✔
7007
  if (diff >= pRateInfo->firstValue) {
8,798,898✔
7008
    diff -= pRateInfo->firstValue;
3,052,042✔
7009
  }
7010

7011
  int64_t duration = pRateInfo->lastKey - pRateInfo->firstKey;
8,798,898✔
7012
  if (duration == 0) {
8,798,898!
7013
    return 0;
×
7014
  }
7015

7016
  return (duration > 0) ? ((double)diff) / (duration / tickPerSec) : 0.0;
8,798,898!
7017
}
7018

7019
static void irateTransferInfoImpl(TSKEY inputKey, SRateInfo* pInput, SRateInfo* pOutput, bool isFirstKey) {
460✔
7020
  if (inputKey > pOutput->lastKey) {
460✔
7021
    doSaveRateInfo(pOutput, true, pOutput->lastKey, pOutput->lastPk, pOutput->lastValue);
194✔
7022
    if (isFirstKey) {
194✔
7023
      doSaveRateInfo(pOutput, false, pInput->firstKey, pInput->firstPk, pInput->firstValue);
47✔
7024
    } else {
7025
      doSaveRateInfo(pOutput, false, pInput->lastKey, pInput->lastPk, pInput->lastValue);
147✔
7026
    }
7027
  } else if ((inputKey < pOutput->lastKey) && (inputKey > pOutput->firstKey)) {
266!
7028
    if (isFirstKey) {
130✔
7029
      doSaveRateInfo(pOutput, true, pInput->firstKey, pInput->firstPk, pInput->firstValue);
92✔
7030
    } else {
7031
      doSaveRateInfo(pOutput, true, pInput->lastKey, pInput->lastPk, pInput->lastValue);
38✔
7032
    }
7033
  } else {
7034
    // inputKey < pOutput->firstKey
7035
  }
7036
}
460✔
7037

7038
static void irateCopyInfo(SRateInfo* pInput, SRateInfo* pOutput) {
6,414,178✔
7039
  doSaveRateInfo(pOutput, true, pInput->firstKey, pInput->firstPk, pInput->firstValue);
6,414,178✔
7040
  doSaveRateInfo(pOutput, false, pInput->lastKey, pInput->lastPk, pInput->lastValue);
6,414,178✔
7041
}
6,414,178✔
7042

7043
static int32_t irateTransferInfo(SRateInfo* pInput, SRateInfo* pOutput) {
6,414,408✔
7044
  if ((pInput->firstKey != INT64_MIN &&
6,414,408✔
7045
       (pInput->firstKey == pOutput->firstKey || pInput->firstKey == pOutput->lastKey)) ||
4,283,145!
7046
      (pInput->lastKey != INT64_MIN && (pInput->lastKey == pOutput->firstKey || pInput->lastKey == pOutput->lastKey))) {
6,414,408!
7047
    return TSDB_CODE_FUNC_DUP_TIMESTAMP;
×
7048
  }
7049

7050
  if (pOutput->hasResult == 0) {
6,414,408✔
7051
    irateCopyInfo(pInput, pOutput);
6,414,178✔
7052
    pOutput->hasResult = pInput->hasResult;
6,414,178✔
7053
    return TSDB_CODE_SUCCESS;
6,414,178✔
7054
  }
7055

7056
  if (pInput->firstKey != INT64_MIN) {
230!
7057
    irateTransferInfoImpl(pInput->firstKey, pInput, pOutput, true);
230✔
7058
  }
7059

7060
  if (pInput->lastKey != INT64_MIN) {
230!
7061
    irateTransferInfoImpl(pInput->lastKey, pInput, pOutput, false);
230✔
7062
  }
7063

7064
  pOutput->hasResult = pInput->hasResult;
230✔
7065
  return TSDB_CODE_SUCCESS;
230✔
7066
}
7067

7068
int32_t irateFunctionMerge(SqlFunctionCtx* pCtx) {
6,414,418✔
7069
  SInputColumnInfoData* pInput = &pCtx->input;
6,414,418✔
7070
  SColumnInfoData*      pCol = pInput->pData[0];
6,414,418✔
7071
  if (pCol->info.type != TSDB_DATA_TYPE_BINARY) {
6,414,418!
7072
    return TSDB_CODE_FUNC_FUNTION_PARA_TYPE;
×
7073
  }
7074

7075
  SRateInfo* pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
6,414,418✔
7076
  initializeRateInfo(pCtx, pInfo, true);
6,414,418✔
7077

7078
  int32_t start = pInput->startRowIndex;
6,414,418✔
7079
  for (int32_t i = start; i < start + pInput->numOfRows; ++i) {
12,828,836✔
7080
    char*      data = colDataGetData(pCol, i);
6,414,418!
7081
    SRateInfo* pInputInfo = (SRateInfo*)varDataVal(data);
6,414,418✔
7082
    initializeRateInfo(pCtx, pInfo, true);
6,414,418✔
7083
    if (pInputInfo->hasResult) {
6,414,418✔
7084
      int32_t code = irateTransferInfo(pInputInfo, pInfo);
6,414,408✔
7085
      if (code != TSDB_CODE_SUCCESS) {
6,414,408!
7086
        return code;
×
7087
      }
7088
    }
7089
  }
7090

7091
  if (pInfo->hasResult) {
6,414,418✔
7092
    GET_RES_INFO(pCtx)->numOfRes = 1;
6,414,408✔
7093
  }
7094

7095
  return TSDB_CODE_SUCCESS;
6,414,418✔
7096
}
7097

7098
int32_t iratePartialFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
6,415,126✔
7099
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
6,415,126✔
7100
  SRateInfo*           pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
6,415,126✔
7101
  int32_t              resultBytes = getIrateInfoSize(pInfo->pkBytes);
6,415,126✔
7102
  char*                res = taosMemoryCalloc(resultBytes + VARSTR_HEADER_SIZE, sizeof(char));
6,415,126!
7103

7104
  if (NULL == res) {
6,415,126!
7105
    return terrno;
×
7106
  }
7107
  (void)memcpy(varDataVal(res), pInfo, resultBytes);
6,415,126✔
7108
  varDataSetLen(res, resultBytes);
6,415,126✔
7109

7110
  int32_t          slotId = pCtx->pExpr->base.resSchema.slotId;
6,415,126✔
7111
  SColumnInfoData* pCol = taosArrayGet(pBlock->pDataBlock, slotId);
6,415,126✔
7112
  if (NULL == pCol) {
6,415,126!
7113
    taosMemoryFree(res);
×
7114
    return TSDB_CODE_OUT_OF_RANGE;
×
7115
  }
7116

7117
  int32_t code = colDataSetVal(pCol, pBlock->info.rows, res, false);
6,415,126✔
7118

7119
  taosMemoryFree(res);
6,415,126!
7120
  return code;
6,415,126✔
7121
}
7122

7123
int32_t irateFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
29,610,759✔
7124
  int32_t          slotId = pCtx->pExpr->base.resSchema.slotId;
29,610,759✔
7125
  SColumnInfoData* pCol = taosArrayGet(pBlock->pDataBlock, slotId);
29,610,759✔
7126
  if (NULL == pCol) {
29,599,852!
7127
    return TSDB_CODE_OUT_OF_RANGE;
×
7128
  }
7129

7130
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
29,599,852✔
7131
  pResInfo->isNullRes = (pResInfo->numOfRes == 0) ? 1 : 0;
29,599,852✔
7132

7133
  SRateInfo* pInfo = GET_ROWCELL_INTERBUF(pResInfo);
29,599,852✔
7134
  double     result = doCalcRate(pInfo, (double)TSDB_TICK_PER_SECOND(pCtx->param[1].param.i));
29,599,852!
7135
  int32_t    code = colDataSetVal(pCol, pBlock->info.rows, (const char*)&result, pResInfo->isNullRes);
29,599,911✔
7136

7137
  return code;
29,599,002✔
7138
}
7139

7140
int32_t groupConstValueFunction(SqlFunctionCtx* pCtx) {
95,229,250✔
7141
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
95,229,250✔
7142
  SGroupKeyInfo*       pInfo = GET_ROWCELL_INTERBUF(pResInfo);
95,229,250✔
7143

7144
  SInputColumnInfoData* pInput = &pCtx->input;
95,229,250✔
7145
  SColumnInfoData*      pInputCol = pInput->pData[0];
95,229,250✔
7146

7147
  int32_t startIndex = pInput->startRowIndex;
95,229,250✔
7148

7149
  // escape rest of data blocks to avoid first entry to be overwritten.
7150
  if (pInfo->hasResult) {
95,229,250✔
7151
    goto _group_value_over;
7,460,421✔
7152
  }
7153

7154
  if (pInputCol->pData == NULL || colDataIsNull_s(pInputCol, startIndex)) {
175,006,827✔
7155
    pInfo->isNull = true;
2,749,258✔
7156
    pInfo->hasResult = true;
2,749,258✔
7157
    goto _group_value_over;
2,749,258✔
7158
  }
7159

7160
  char* data = colDataGetData(pInputCol, startIndex);
85,019,571!
7161
  if (IS_VAR_DATA_TYPE(pInputCol->info.type)) {
85,019,571!
7162
    int32_t bytes = calcStrBytesByType(pInputCol->info.type, data);
69,386,325✔
7163
    (void)memcpy(pInfo->data, data, bytes);
69,375,995✔
7164
  } else {
7165
    (void)memcpy(pInfo->data, data, pInputCol->info.bytes);
15,633,246✔
7166
  }
7167
  pInfo->hasResult = true;
85,009,241✔
7168

7169
_group_value_over:
95,218,920✔
7170

7171
  SET_VAL(pResInfo, 1, 1);
95,218,920✔
7172
  return TSDB_CODE_SUCCESS;
95,218,920✔
7173
}
7174

7175
int32_t groupKeyFunction(SqlFunctionCtx* pCtx) { return groupConstValueFunction(pCtx); }
95,233,460✔
7176

7177
int32_t groupConstValueFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
86,232,383✔
7178
  int32_t          slotId = pCtx->pExpr->base.resSchema.slotId;
86,232,383✔
7179
  int32_t          code = TSDB_CODE_SUCCESS;
86,232,383✔
7180
  SColumnInfoData* pCol = taosArrayGet(pBlock->pDataBlock, slotId);
86,232,383✔
7181
  if (NULL == pCol) {
86,167,709!
7182
    return TSDB_CODE_OUT_OF_RANGE;
×
7183
  }
7184

7185
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
86,167,709✔
7186

7187
  SGroupKeyInfo* pInfo = GET_ROWCELL_INTERBUF(pResInfo);
86,167,709✔
7188

7189
  if (pInfo->hasResult) {
86,167,709!
7190
    int32_t currentRow = pBlock->info.rows;
86,196,242✔
7191
    for (; currentRow < pBlock->info.rows + pResInfo->numOfRes; ++currentRow) {
173,037,821✔
7192
      code = colDataSetVal(pCol, currentRow, pInfo->data, pInfo->isNull ? true : false);
86,247,769✔
7193
      if (TSDB_CODE_SUCCESS != code) {
86,841,579!
7194
        return code;
×
7195
      }
7196
    }
7197
  } else {
7198
    pResInfo->numOfRes = 0;
×
7199
  }
7200

7201
  return code;
86,761,519✔
7202
}
7203

7204
int32_t groupKeyFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) { return groupConstValueFinalize(pCtx, pBlock); }
86,171,259✔
7205

7206
int32_t groupKeyCombine(SqlFunctionCtx* pDestCtx, SqlFunctionCtx* pSourceCtx) {
×
7207
  SResultRowEntryInfo* pDResInfo = GET_RES_INFO(pDestCtx);
×
7208
  SGroupKeyInfo*       pDBuf = GET_ROWCELL_INTERBUF(pDResInfo);
×
7209

7210
  SResultRowEntryInfo* pSResInfo = GET_RES_INFO(pSourceCtx);
×
7211
  SGroupKeyInfo*       pSBuf = GET_ROWCELL_INTERBUF(pSResInfo);
×
7212

7213
  // escape rest of data blocks to avoid first entry to be overwritten.
7214
  if (pDBuf->hasResult) {
×
7215
    goto _group_key_over;
×
7216
  }
7217

7218
  if (pSBuf->isNull) {
×
7219
    pDBuf->isNull = true;
×
7220
    pDBuf->hasResult = true;
×
7221
    goto _group_key_over;
×
7222
  }
7223

7224
  if (IS_VAR_DATA_TYPE(pSourceCtx->resDataInfo.type)) {
×
7225
    int32_t bytes = calcStrBytesByType(pSourceCtx->resDataInfo.type, pSBuf->data);
×
7226
    (void)memcpy(pDBuf->data, pSBuf->data, bytes);
×
7227
  } else {
7228
    (void)memcpy(pDBuf->data, pSBuf->data, pSourceCtx->resDataInfo.bytes);
×
7229
  }
7230

7231
  pDBuf->hasResult = true;
×
7232

7233
_group_key_over:
×
7234

7235
  SET_VAL(pDResInfo, 1, 1);
×
7236
  return TSDB_CODE_SUCCESS;
×
7237
}
7238

7239
int32_t cachedLastRowFunction(SqlFunctionCtx* pCtx) {
7,456✔
7240
  int32_t numOfElems = 0;
7,456✔
7241

7242
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
7,456✔
7243
  SFirstLastRes*       pInfo = GET_ROWCELL_INTERBUF(pResInfo);
7,456✔
7244

7245
  SInputColumnInfoData* pInput = &pCtx->input;
7,456✔
7246
  SColumnInfoData*      pInputCol = pInput->pData[0];
7,456✔
7247

7248
  int32_t bytes = pInputCol->info.bytes;
7,456✔
7249
  pInfo->bytes = bytes;
7,456✔
7250

7251
  SColumnInfoData* pkCol = pInput->pPrimaryKey;
7,456✔
7252
  pInfo->pkType = -1;
7,456✔
7253
  __compar_fn_t pkCompareFn = NULL;
7,456✔
7254
  if (pCtx->hasPrimaryKey) {
7,456✔
7255
    pInfo->pkType = pkCol->info.type;
978✔
7256
    pInfo->pkBytes = pkCol->info.bytes;
978✔
7257
    pkCompareFn = getKeyComparFunc(pInfo->pkType, TSDB_ORDER_DESC);
978✔
7258
  }
7259

7260
  // TODO it traverse the different way.
7261
  // last_row function does not ignore the null value
7262
  for (int32_t i = pInput->numOfRows + pInput->startRowIndex - 1; i >= pInput->startRowIndex; --i) {
14,923✔
7263
    numOfElems++;
7,466✔
7264

7265
    bool  isNull = colDataIsNull(pInputCol, pInput->numOfRows, i, NULL);
7,466✔
7266
    char* data = isNull ? NULL : colDataGetData(pInputCol, i);
7,466!
7267

7268
    TSKEY cts = getRowPTs(pInput->pPTS, i);
7,466!
7269
    if (pResInfo->numOfRes == 0 || pInfo->ts < cts) {
7,466✔
7270
      int32_t code = doSaveLastrow(pCtx, data, i, cts, pInfo);
6,493✔
7271
      if (code != TSDB_CODE_SUCCESS) {
6,494!
7272
        return code;
×
7273
      }
7274
      pResInfo->numOfRes = 1;
6,494✔
7275
    }
7276
  }
7277

7278
  SET_VAL(pResInfo, numOfElems, 1);
7,457!
7279
  return TSDB_CODE_SUCCESS;
7,457✔
7280
}
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