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

taosdata / TDengine / #4976

06 Mar 2026 09:48AM UTC coverage: 68.446% (+0.08%) from 68.37%
#4976

push

travis-ci

web-flow
feat(TDgpt): support multiple input data columns for anomaly detection. (#34606)

0 of 93 new or added lines in 9 files covered. (0.0%)

5718 existing lines in 144 files now uncovered.

211146 of 308486 relevant lines covered (68.45%)

136170362.0 hits per line

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

77.68
/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 "tarray.h"
25
#include "tcompare.h"
26
#include "tdatablock.h"
27
#include "tdigest.h"
28
#include "tfunctionInt.h"
29
#include "tglobal.h"
30
#include "thistogram.h"
31
#include "tpercentile.h"
32
#include "ttypes.h"
33

34
bool ignoreNegative(int8_t ignoreOption) { return (ignoreOption & 0x1) == 0x1; }
2,147,483,647✔
35
bool ignoreNull(int8_t ignoreOption) { return (ignoreOption & 0x2) == 0x2; }
43,525,103✔
36

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

197
void funcInputUpdate(SqlFunctionCtx* pCtx) {
53,246,255✔
198
  SFuncInputRowIter* pIter = &pCtx->rowIter;
53,246,255✔
199

200
  if (!pCtx->bInputFinished) {
53,246,255✔
201
    pIter->pInput = &pCtx->input;
53,246,255✔
202
    pIter->tsList = (TSKEY*)pIter->pInput->pPTS->pData;
53,246,255✔
203
    pIter->pDataCol = pIter->pInput->pData[0];
53,245,840✔
204
    pIter->pPkCol = pIter->pInput->pPrimaryKey;
53,246,255✔
205
    pIter->rowIndex = pIter->pInput->startRowIndex;
53,246,255✔
206
    pIter->inputEndIndex = pIter->rowIndex + pIter->pInput->numOfRows - 1;
53,246,255✔
207
    pIter->pSrcBlock = pCtx->pSrcBlock;
53,246,255✔
208
    if (!pIter->hasGroupId || pIter->groupId != pIter->pSrcBlock->info.id.groupId) {
53,246,255✔
209
      pIter->hasGroupId = true;
6,478,838✔
210
      pIter->groupId = pIter->pSrcBlock->info.id.groupId;
6,479,253✔
211
      pIter->hasPrev = false;
6,478,838✔
212
    }
213
  } else {
214
    pIter->finalRow = true;
×
215
  }
216
}
53,245,840✔
217

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

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

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

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

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

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

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

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

332
static void forwardToNextDiffTsRow(SFuncInputRowIter* pIter, int32_t rowIndex) {
3,357,826✔
333
  int32_t idx = rowIndex + 1;
3,357,826✔
334
  while (idx <= pIter->inputEndIndex && pIter->tsList[idx] == pIter->tsList[rowIndex]) {
47,724,432✔
335
    ++idx;
44,366,606✔
336
  }
337
  pIter->rowIndex = idx;
3,357,826✔
338
}
3,357,826✔
339

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

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

361
      pIter->hasPrev = false;
353,934✔
362
      setInputRowInfo(pRow, pIter, idx, true);
353,934✔
363
      forwardToNextDiffTsRow(pIter, idx);
353,934✔
364
      return true;
353,934✔
365
    }
366
  } else {
367
    if (pIter->rowIndex <= pIter->inputEndIndex) {
4,119,304✔
368
      setInputRowInfo(pRow, pIter, pIter->rowIndex, true);
3,562,014✔
369

370
      TSKEY tsEnd = pIter->tsList[pIter->inputEndIndex];
3,562,014✔
371
      if (pIter->tsList[pIter->rowIndex] != tsEnd) {
3,562,014✔
372
        forwardToNextDiffTsRow(pIter, pIter->rowIndex);
3,003,892✔
373
      } else {
374
        pIter->rowIndex = pIter->inputEndIndex + 1;
558,122✔
375
      }
376
      return true;
3,562,014✔
377
    } else {
378
      TSKEY tsEnd = pIter->tsList[pIter->inputEndIndex];
557,290✔
379
      pIter->hasPrev = true;
557,290✔
380
      pIter->prevBlockTsEnd = tsEnd;
557,290✔
381
      return false;
557,290✔
382
    }
383
  }
384
}
385

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

513
  return code;
78,550✔
514
}
515

516
EFuncDataRequired countDataRequired(SFunctionNode* pFunc, STimeWindow* pTimeWindow) {
13,760,630✔
517
  SNode* pParam = nodesListGetNode(pFunc->pParameterList, 0);
13,760,630✔
518
  if (QUERY_NODE_COLUMN == nodeType(pParam) && PRIMARYKEY_TIMESTAMP_COL_ID == ((SColumnNode*)pParam)->colId) {
13,761,994✔
519
    return FUNC_DATA_REQUIRED_NOT_LOAD;
10,050,768✔
520
  }
521
  return FUNC_DATA_REQUIRED_SMA_LOAD;
3,711,148✔
522
}
523

524
bool getCountFuncEnv(SFunctionNode* UNUSED_PARAM(pFunc), SFuncExecEnv* pEnv) {
50,357,445✔
525
  pEnv->calcMemSize = sizeof(int64_t);
50,357,445✔
526
  return true;
50,374,621✔
527
}
528

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

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

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

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

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

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

585
  if (tsCountAlwaysReturnValue) {
2,147,483,647✔
586
    pResInfo->numOfRes = 1;
2,147,483,647✔
587
  } else {
588
    SET_VAL(pResInfo, val, 1);
8,773,402✔
589
  }
590

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

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

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

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

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

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

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

618
  if (IS_NULL_TYPE(type)) {
2,147,483,647✔
619
    numOfElem = 0;
1,545,959,379✔
620
    goto _sum_over;
1,545,959,379✔
621
  }
622

623
  if (pInput->colDataSMAIsSet) {
2,147,483,647✔
624
    numOfElem = pInput->numOfRows - pAgg->numOfNull;
28,831,054✔
625

626
    if (IS_SIGNED_NUMERIC_TYPE(type)) {
28,830,469✔
627
      SUM_RES_INC_ISUM(pSumRes, pAgg->sum);
14,691,824✔
628
    } else if (IS_UNSIGNED_NUMERIC_TYPE(type)) {
14,138,645✔
629
      SUM_RES_INC_USUM(pSumRes, pAgg->sum);
14,137,215✔
630
    } else if (IS_FLOAT_TYPE(type)) {
1,430✔
631
      SUM_RES_INC_DSUM(pSumRes, GET_DOUBLE_VAL((const char*)&(pAgg->sum)));
×
632
    } else if (IS_DECIMAL_TYPE(type)) {
7,865✔
633
      SUM_RES_SET_TYPE(pSumRes, pCtx->inputType, TSDB_DATA_TYPE_DECIMAL);
7,865✔
634
      const SDecimalOps* pOps = getDecimalOps(TSDB_DATA_TYPE_DECIMAL);
7,865✔
635
      if (pAgg->overflow || decimal128AddCheckOverflow((Decimal*)&SUM_RES_GET_DECIMAL_SUM(pSumRes),
14,300✔
636
                                                       &pAgg->decimal128Sum, DECIMAL_WORD_NUM(Decimal))) {
6,435✔
637
        return TSDB_CODE_DECIMAL_OVERFLOW;
1,430✔
638
      }
639
      pOps->add(&SUM_RES_GET_DECIMAL_SUM(pSumRes), &pAgg->decimal128Sum, DECIMAL_WORD_NUM(Decimal));
6,435✔
640
    }
641
  } else {  // computing based on the true data block
642
    SColumnInfoData* pCol = pInput->pData[0];
2,147,483,647✔
643

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

647
    if (IS_SIGNED_NUMERIC_TYPE(type) || type == TSDB_DATA_TYPE_BOOL) {
2,147,483,647✔
648
      if (type == TSDB_DATA_TYPE_TINYINT || type == TSDB_DATA_TYPE_BOOL) {
2,147,483,647✔
649
        LIST_ADD_N(SUM_RES_GET_ISUM(pSumRes), pCol, start, numOfRows, int8_t, numOfElem);
2,147,483,647✔
650
      } else if (type == TSDB_DATA_TYPE_SMALLINT) {
2,147,483,647✔
651
        LIST_ADD_N(SUM_RES_GET_ISUM(pSumRes), pCol, start, numOfRows, int16_t, numOfElem);
2,147,483,647✔
652
      } else if (type == TSDB_DATA_TYPE_INT) {
2,147,483,647✔
653
        LIST_ADD_N(SUM_RES_GET_ISUM(pSumRes), pCol, start, numOfRows, int32_t, numOfElem);
2,147,483,647✔
654
      } else if (type == TSDB_DATA_TYPE_BIGINT) {
1,147,990,134✔
655
        LIST_ADD_N(SUM_RES_GET_ISUM(pSumRes), pCol, start, numOfRows, int64_t, numOfElem);
2,147,483,647✔
656
      }
657
    } else if (IS_UNSIGNED_NUMERIC_TYPE(type)) {
2,147,483,647✔
658
      if (type == TSDB_DATA_TYPE_UTINYINT) {
2,147,483,647✔
659
        LIST_ADD_N(SUM_RES_GET_USUM(pSumRes), pCol, start, numOfRows, uint8_t, numOfElem);
2,147,483,647✔
660
      } else if (type == TSDB_DATA_TYPE_USMALLINT) {
2,147,483,647✔
661
        LIST_ADD_N(SUM_RES_GET_USUM(pSumRes), pCol, start, numOfRows, uint16_t, numOfElem);
2,147,483,647✔
662
      } else if (type == TSDB_DATA_TYPE_UINT) {
5,748,592✔
663
        LIST_ADD_N(SUM_RES_GET_USUM(pSumRes), pCol, start, numOfRows, uint32_t, numOfElem);
2,147,483,647✔
664
      } else if (type == TSDB_DATA_TYPE_UBIGINT) {
3,158,279✔
665
        LIST_ADD_N(SUM_RES_GET_USUM(pSumRes), pCol, start, numOfRows, uint64_t, numOfElem);
2,147,483,647✔
666
      }
667
    } else if (type == TSDB_DATA_TYPE_DOUBLE) {
201,835,186✔
668
      LIST_ADD_N(SUM_RES_GET_DSUM(pSumRes), pCol, start, numOfRows, double, numOfElem);
458,553,068✔
669
    } else if (type == TSDB_DATA_TYPE_FLOAT) {
136,780,828✔
670
      LIST_ADD_N(SUM_RES_GET_DSUM(pSumRes), pCol, start, numOfRows, float, numOfElem);
378,240,051✔
671
    } else if (IS_DECIMAL_TYPE(type)) {
21,988✔
672
      SUM_RES_SET_TYPE(pSumRes, pCtx->inputType, TSDB_DATA_TYPE_DECIMAL);
21,988✔
673
      int32_t overflow = false;
21,450✔
674
      if (TSDB_DATA_TYPE_DECIMAL64 == type) {
21,450✔
675
        LIST_ADD_DECIMAL_N(&SUM_RES_GET_DECIMAL_SUM(pSumRes), pCol, start, numOfRows, Decimal64, numOfElem);
5,725,720✔
676
      } else if (TSDB_DATA_TYPE_DECIMAL == type) {
15,730✔
677
        LIST_ADD_DECIMAL_N(&SUM_RES_GET_DECIMAL_SUM(pSumRes), pCol, start, numOfRows, Decimal128, numOfElem);
11,460,020✔
678
      }
679
      if (overflow) return TSDB_CODE_DECIMAL_OVERFLOW;
21,450✔
680
    }
681
  }
682

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

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

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

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

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

724
bool getSumFuncEnv(SFunctionNode* pFunc, SFuncExecEnv* pEnv) {
24,687,790✔
725
  pEnv->calcMemSize = SUM_RES_GET_SIZE(pFunc->node.resType.type);
24,687,790✔
726
  return true;
24,693,566✔
727
}
728

729
static bool funcNotSupportStringSma(SFunctionNode* pFunc) {
20,986,534✔
730
  SNode* pParam;
731
  switch (pFunc->funcType) {
20,986,534✔
732
    case FUNCTION_TYPE_MAX:
20,989,796✔
733
    case FUNCTION_TYPE_MIN:
734
    case FUNCTION_TYPE_SUM:
735
    case FUNCTION_TYPE_AVG:
736
    case FUNCTION_TYPE_AVG_PARTIAL:
737
    case FUNCTION_TYPE_PERCENTILE:
738
    case FUNCTION_TYPE_SPREAD:
739
    case FUNCTION_TYPE_SPREAD_PARTIAL:
740
    case FUNCTION_TYPE_SPREAD_MERGE:
741
    case FUNCTION_TYPE_TWA:
742
    case FUNCTION_TYPE_ELAPSED:
743
      pParam = nodesListGetNode(pFunc->pParameterList, 0);
20,989,796✔
744
      if (pParam && nodesIsExprNode(pParam) && (IS_VAR_DATA_TYPE(((SExprNode*)pParam)->resType.type))) {
20,990,427✔
745
        return true;
1,115,264✔
746
      }
747
      break;
19,876,371✔
UNCOV
748
    default:
×
UNCOV
749
      break;
×
750
  }
751
  return false;
19,873,109✔
752
}
753

754
EFuncDataRequired statisDataRequired(SFunctionNode* pFunc, STimeWindow* pTimeWindow) {
20,986,662✔
755
  if (funcNotSupportStringSma(pFunc)) {
20,986,662✔
756
    return FUNC_DATA_REQUIRED_DATA_LOAD;
1,115,264✔
757
  }
758
  return FUNC_DATA_REQUIRED_SMA_LOAD;
19,876,652✔
759
}
760

761
int32_t minmaxFunctionSetup(SqlFunctionCtx* pCtx, SResultRowEntryInfo* pResultInfo) {
2,147,483,647✔
762
  if (pResultInfo->initialized) {
2,147,483,647✔
763
    return TSDB_CODE_SUCCESS;
×
764
  }
765
  if (TSDB_CODE_SUCCESS != functionSetup(pCtx, pResultInfo)) {
2,147,483,647✔
766
    return TSDB_CODE_FUNC_SETUP_ERROR;  // not initialized since it has been initialized
×
767
  }
768

769
  SMinmaxResInfo* buf = GET_ROWCELL_INTERBUF(pResultInfo);
2,147,483,647✔
770
  buf->assign = false;
2,147,483,647✔
771
  buf->tuplePos.pageId = -1;
2,147,483,647✔
772

773
  buf->nullTupleSaved = false;
2,147,483,647✔
774
  buf->nullTuplePos.pageId = -1;
2,147,483,647✔
775
  buf->str = NULL;
2,147,483,647✔
776
  return TSDB_CODE_SUCCESS;
2,147,483,647✔
777
}
778

779
bool getMinmaxFuncEnv(SFunctionNode* UNUSED_PARAM(pFunc), SFuncExecEnv* pEnv) {
44,572,114✔
780
  COMPILE_TIME_ASSERT(sizeof(SMinmaxResInfo) == sizeof(SOldMinMaxResInfo));
781
  pEnv->calcMemSize = sizeof(SMinmaxResInfo);
44,572,114✔
782
  return true;
44,574,048✔
783
}
784

785
int32_t minFunction(SqlFunctionCtx* pCtx) {
2,147,483,647✔
786
  int32_t numOfElems = 0;
2,147,483,647✔
787
  int32_t code = doMinMaxHelper(pCtx, 1, &numOfElems);
2,147,483,647✔
788
  if (code != TSDB_CODE_SUCCESS) {
2,147,483,647✔
789
    return code;
×
790
  }
791
  SET_VAL(GET_RES_INFO(pCtx), numOfElems, 1);
2,147,483,647✔
792
  return TSDB_CODE_SUCCESS;
2,147,483,647✔
793
}
794

795
int32_t maxFunction(SqlFunctionCtx* pCtx) {
2,147,483,647✔
796
  int32_t numOfElems = 0;
2,147,483,647✔
797
  int32_t code = doMinMaxHelper(pCtx, 0, &numOfElems);
2,147,483,647✔
798
  if (code != TSDB_CODE_SUCCESS) {
2,147,483,647✔
799
    return code;
×
800
  }
801
  SET_VAL(GET_RES_INFO(pCtx), numOfElems, 1);
2,147,483,647✔
802
  return TSDB_CODE_SUCCESS;
2,147,483,647✔
803
}
804

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

809
int32_t minmaxFunctionFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
2,147,483,647✔
810
  int32_t code = TSDB_CODE_SUCCESS;
2,147,483,647✔
811

812
  SResultRowEntryInfo* pEntryInfo = GET_RES_INFO(pCtx);
2,147,483,647✔
813
  SMinmaxResInfo*      pRes = GET_ROWCELL_INTERBUF(pEntryInfo);
2,147,483,647✔
814

815
  int32_t slotId = pCtx->pExpr->base.resSchema.slotId;
2,147,483,647✔
816
  int32_t currentRow = pBlock->info.rows;
2,147,483,647✔
817

818
  SColumnInfoData* pCol = taosArrayGet(pBlock->pDataBlock, slotId);
2,147,483,647✔
819
  if (NULL == pCol) {
2,147,483,647✔
820
    return TSDB_CODE_OUT_OF_RANGE;
×
821
  }
822
  pEntryInfo->isNullRes = (pEntryInfo->numOfRes == 0) ? 1 : 0;
2,147,483,647✔
823

824
  // NOTE: do nothing change it, for performance issue
825
  if (!pEntryInfo->isNullRes) {
2,147,483,647✔
826
    switch (pCol->info.type) {
1,902,063,747✔
827
      case TSDB_DATA_TYPE_UBIGINT:
129,447,682✔
828
      case TSDB_DATA_TYPE_BIGINT:
829
      case TSDB_DATA_TYPE_TIMESTAMP:
830
        ((int64_t*)pCol->pData)[currentRow] = pRes->v;
129,447,682✔
831
        break;
129,446,590✔
832
      case TSDB_DATA_TYPE_UINT:
1,687,618,308✔
833
      case TSDB_DATA_TYPE_INT:
834
        colDataSetInt32(pCol, currentRow, (int32_t*)&pRes->v);
1,687,618,308✔
835
        break;
1,687,616,789✔
836
      case TSDB_DATA_TYPE_USMALLINT:
3,420,217✔
837
      case TSDB_DATA_TYPE_SMALLINT:
838
        colDataSetInt16(pCol, currentRow, (int16_t*)&pRes->v);
3,420,217✔
839
        break;
3,420,217✔
840
      case TSDB_DATA_TYPE_BOOL:
19,673,718✔
841
      case TSDB_DATA_TYPE_UTINYINT:
842
      case TSDB_DATA_TYPE_TINYINT:
843
        colDataSetInt8(pCol, currentRow, (int8_t*)&pRes->v);
19,673,718✔
844
        break;
19,673,718✔
845
      case TSDB_DATA_TYPE_DOUBLE:
28,858,067✔
846
        colDataSetDouble(pCol, currentRow, (double*)&pRes->v);
28,858,067✔
847
        break;
28,858,067✔
848
      case TSDB_DATA_TYPE_FLOAT: {
24,643,397✔
849
        float v = GET_FLOAT_VAL(&pRes->v);
24,643,397✔
850
        colDataSetFloat(pCol, currentRow, &v);
24,643,397✔
851
        break;
24,643,397✔
852
      }
853
      case TSDB_DATA_TYPE_VARBINARY:
7,765,851✔
854
      case TSDB_DATA_TYPE_VARCHAR:
855
      case TSDB_DATA_TYPE_NCHAR: {
856
        code = colDataSetVal(pCol, currentRow, pRes->str, false);
7,765,851✔
857
        if (TSDB_CODE_SUCCESS != code) {
7,765,851✔
UNCOV
858
          return code;
×
859
        }
860
        break;
7,765,851✔
861
      }
862
      case TSDB_DATA_TYPE_DECIMAL64:
606,164✔
863
        code = colDataSetVal(pCol, currentRow, (const char*)&pRes->v, false);
606,164✔
864
        break;
606,164✔
865
      case TSDB_DATA_TYPE_DECIMAL:
29,699✔
866
        code = colDataSetVal(pCol, currentRow, (void*)pRes->dec, false);
29,699✔
867
        break;
29,699✔
868
    }
869
  } else {
870
    colDataSetNULL(pCol, currentRow);
498,873,309✔
871
  }
872

873
  if (IS_VAR_DATA_TYPE(pCol->info.type)) taosMemoryFreeClear(pRes->str);
2,147,483,647✔
874
  if (pCtx->subsidiaries.num > 0) {
2,147,483,647✔
875
    if (pEntryInfo->numOfRes > 0) {
2,075,459✔
876
      code = setSelectivityValue(pCtx, pBlock, &pRes->tuplePos, currentRow);
1,816,027✔
877
    } else {
878
      code = setNullSelectivityValue(pCtx, pBlock, currentRow);
259,432✔
879
    }
880
  }
881

882
  return code;
2,147,483,647✔
883
}
884

885
int32_t setNullSelectivityValue(SqlFunctionCtx* pCtx, SSDataBlock* pBlock, int32_t rowIndex) {
2,084,639,696✔
886
  if (pCtx->subsidiaries.num <= 0) {
2,084,639,696✔
887
    return TSDB_CODE_SUCCESS;
2,084,322,303✔
888
  }
889

890
  for (int32_t j = 0; j < pCtx->subsidiaries.num; ++j) {
877,756✔
891
    SqlFunctionCtx* pc = pCtx->subsidiaries.pCtx[j];
547,620✔
892
    int32_t         dstSlotId = pc->pExpr->base.resSchema.slotId;
547,620✔
893

894
    SColumnInfoData* pDstCol = taosArrayGet(pBlock->pDataBlock, dstSlotId);
547,620✔
895
    if (NULL == pDstCol) {
547,620✔
UNCOV
896
      return terrno;
×
897
    }
898
    colDataSetNULL(pDstCol, rowIndex);
547,620✔
899
  }
900

901
  return TSDB_CODE_SUCCESS;
330,136✔
902
}
903

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

909
  if ((pCtx->saveHandle.pBuf != NULL && pTuplePos->pageId != -1) ||
101,732,512✔
910
      (pCtx->saveHandle.pState && pTuplePos->streamTupleKey.ts > 0)) {
1,204✔
911
    int32_t numOfCols = pCtx->subsidiaries.num;
101,731,308✔
912
    char*   p = NULL;
101,731,308✔
913
    int32_t code = loadTupleData(pCtx, pTuplePos, &p);
101,731,910✔
914
    if (p == NULL || TSDB_CODE_SUCCESS != code) {
101,730,706✔
UNCOV
915
      qError("Load tuple data failed since %s, groupId:%" PRIu64 ", ts:%" PRId64, terrstr(),
×
916
             pTuplePos->streamTupleKey.groupId, pTuplePos->streamTupleKey.ts);
UNCOV
917
      return TSDB_CODE_NOT_FOUND;
×
918
    }
919

920
    bool* nullList = (bool*)p;
101,731,308✔
921
    char* pStart = (char*)(nullList + numOfCols * sizeof(bool));
101,731,308✔
922

923
    // todo set the offset value to optimize the performance.
924
    for (int32_t j = 0; j < numOfCols; ++j) {
336,423,534✔
925
      SqlFunctionCtx* pc = pCtx->subsidiaries.pCtx[j];
234,691,624✔
926
      int32_t         dstSlotId = pc->pExpr->base.resSchema.slotId;
234,692,226✔
927

928
      SColumnInfoData* pDstCol = taosArrayGet(pBlock->pDataBlock, dstSlotId);
234,692,828✔
929
      if (NULL == pDstCol) {
234,692,828✔
UNCOV
930
        return terrno;
×
931
      }
932
      if (nullList[j]) {
234,692,828✔
933
        colDataSetNULL(pDstCol, rowIndex);
83,385,262✔
934
      } else {
935
        code = colDataSetValOrCover(pDstCol, rowIndex, pStart, false);
151,306,362✔
936
        if (TSDB_CODE_SUCCESS != code) {
151,307,566✔
UNCOV
937
          return code;
×
938
        }
939
      }
940
      pStart += pDstCol->info.bytes;
234,692,828✔
941
    }
942
  }
943

944
  return TSDB_CODE_SUCCESS;
101,731,910✔
945
}
946

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

954
  int32_t code = TSDB_CODE_SUCCESS;
948,896✔
955
  for (int32_t j = 0; j < pCtx->subsidiaries.num; ++j) {
2,150,578✔
956
    SqlFunctionCtx* pc = pCtx->subsidiaries.pCtx[j];
1,201,682✔
957

958
    // get data from source col
959
    SFunctParam* pFuncParam = &pc->pExpr->base.pParam[0];
1,201,682✔
960
    int32_t      srcSlotId = pFuncParam->pCol->slotId;
1,201,682✔
961

962
    SColumnInfoData* pSrcCol = taosArrayGet(pCtx->pSrcBlock->pDataBlock, srcSlotId);
1,201,682✔
963
    if (NULL == pSrcCol) {
1,201,682✔
UNCOV
964
      return TSDB_CODE_OUT_OF_RANGE;
×
965
    }
966

967
    char* pData = colDataGetData(pSrcCol, rowIndex);
1,201,682✔
968

969
    // append to dest col
970
    int32_t dstSlotId = pc->pExpr->base.resSchema.slotId;
1,201,682✔
971

972
    SColumnInfoData* pDstCol = taosArrayGet(pCtx->pDstBlock->pDataBlock, dstSlotId);
1,201,682✔
973
    if (NULL == pDstCol) {
1,201,682✔
UNCOV
974
      return TSDB_CODE_OUT_OF_RANGE;
×
975
    }
976

977
    if (colDataIsNull_s(pSrcCol, rowIndex) == true) {
2,403,364✔
978
      colDataSetNULL(pDstCol, pos);
50,076✔
979
    } else {
980
      code = colDataSetVal(pDstCol, pos, pData, false);
1,151,606✔
981
      if (TSDB_CODE_SUCCESS != code) {
1,151,606✔
UNCOV
982
        return code;
×
983
      }
984
    }
985
  }
986
  return code;
948,896✔
987
}
988

UNCOV
989
void replaceTupleData(STuplePos* pDestPos, STuplePos* pSourcePos) { *pDestPos = *pSourcePos; }
×
990

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

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

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

UNCOV
1075
int32_t minCombine(SqlFunctionCtx* pDestCtx, SqlFunctionCtx* pSourceCtx) {
×
1076
  return minMaxCombine(pDestCtx, pSourceCtx, 1);
×
1077
}
UNCOV
1078
int32_t maxCombine(SqlFunctionCtx* pDestCtx, SqlFunctionCtx* pSourceCtx) {
×
UNCOV
1079
  return minMaxCombine(pDestCtx, pSourceCtx, 0);
×
1080
}
1081

1082
int32_t getStdInfoSize() { return (int32_t)sizeof(SStdRes); }
17,614,618✔
1083

1084
bool getStdFuncEnv(SFunctionNode* pFunc, SFuncExecEnv* pEnv) {
4,630,693✔
1085
  pEnv->calcMemSize = sizeof(SStdRes);
4,630,693✔
1086
  return true;
4,632,901✔
1087
}
1088

1089
int32_t stdFunctionSetup(SqlFunctionCtx* pCtx, SResultRowEntryInfo* pResultInfo) {
733,561,792✔
1090
  if (pResultInfo->initialized) {
733,561,792✔
UNCOV
1091
    return TSDB_CODE_SUCCESS;
×
1092
  }
1093
  if (TSDB_CODE_SUCCESS != functionSetup(pCtx, pResultInfo)) {
733,561,792✔
UNCOV
1094
    return TSDB_CODE_FUNC_SETUP_ERROR;
×
1095
  }
1096

1097
  SStdRes* pRes = GET_ROWCELL_INTERBUF(pResultInfo);
733,563,330✔
1098
  (void)memset(pRes, 0, sizeof(SStdRes));
733,561,274✔
1099
  return TSDB_CODE_SUCCESS;
733,561,274✔
1100
}
1101

1102
int32_t stdFunction(SqlFunctionCtx* pCtx) {
1,078,750,323✔
1103
  int32_t numOfElem = 0;
1,078,750,323✔
1104

1105
  // Only the pre-computing information loaded and actual data does not loaded
1106
  SInputColumnInfoData* pInput = &pCtx->input;
1,078,750,323✔
1107
  int32_t               type = pInput->pData[0]->info.type;
1,078,755,932✔
1108

1109
  SStdRes* pStdRes = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
1,078,762,830✔
1110
  pStdRes->type = type;
1,078,613,976✔
1111

1112
  // computing based on the true data block
1113
  SColumnInfoData* pCol = pInput->pData[0];
1,078,765,801✔
1114

1115
  int32_t start = pInput->startRowIndex;
1,078,757,443✔
1116
  int32_t numOfRows = pInput->numOfRows;
1,078,749,848✔
1117

1118
  if (IS_NULL_TYPE(type)) {
1,078,760,135✔
1119
    numOfElem = 0;
95,357,372✔
1120
    goto _stddev_over;
95,357,372✔
1121
  }
1122

1123
  switch (type) {
983,402,763✔
1124
    case TSDB_DATA_TYPE_TINYINT: {
18,820,646✔
1125
      int8_t* plist = (int8_t*)pCol->pData;
18,820,646✔
1126
      for (int32_t i = start; i < numOfRows + start; ++i) {
2,147,483,647✔
1127
        if (pCol->hasNull && colDataIsNull_f(pCol, i)) {
2,147,483,647✔
1128
          continue;
2,147,483,647✔
1129
        }
1130

1131
        numOfElem += 1;
1,549,314,042✔
1132
        pStdRes->count += 1;
1,549,314,042✔
1133
        double nr = (double)plist[i];
1,560,433,739✔
1134
        if (pStdRes->count == 1) {
1,560,466,559✔
1135
          pStdRes->dsum = nr;
591,501✔
1136
        } else {
1137
          double          s_kminusone = pStdRes->dsum;
1,559,917,298✔
1138
          volatile double diff = nr - s_kminusone;
1,559,882,703✔
1139
          pStdRes->dsum = s_kminusone + diff / (double)pStdRes->count;
1,559,882,703✔
1140
          pStdRes->quadraticDSum += diff * (nr - pStdRes->dsum);
1,559,933,778✔
1141
        }
1142
      }
1143

1144
      break;
18,550,395✔
1145
    }
1146

1147
    case TSDB_DATA_TYPE_SMALLINT: {
831,766,463✔
1148
      int16_t* plist = (int16_t*)pCol->pData;
831,766,463✔
1149
      for (int32_t i = start; i < numOfRows + pInput->startRowIndex; ++i) {
2,147,483,647✔
1150
        if (pCol->hasNull && colDataIsNull_f(pCol, i)) {
2,147,483,647✔
1151
          continue;
2,147,483,647✔
1152
        }
1153

1154
        numOfElem += 1;
2,147,483,647✔
1155
        pStdRes->count += 1;
2,147,483,647✔
1156
        double nr = (double)plist[i];
2,147,483,647✔
1157
        if (pStdRes->count == 1) {
2,147,483,647✔
1158
          pStdRes->dsum = nr;
457,689,305✔
1159
        } else {
1160
          double          s_kminusone = pStdRes->dsum;
1,819,307,080✔
1161
          volatile double diff = nr - s_kminusone;
1,819,166,484✔
1162
          pStdRes->dsum = s_kminusone + diff / (double)pStdRes->count;
1,819,166,484✔
1163
          pStdRes->quadraticDSum += diff * (nr - pStdRes->dsum);
1,819,272,570✔
1164
        }
1165
      }
1166
      break;
831,764,698✔
1167
    }
1168

1169
    case TSDB_DATA_TYPE_INT: {
35,794,594✔
1170
      int32_t* plist = (int32_t*)pCol->pData;
35,794,594✔
1171
      for (int32_t i = start; i < numOfRows + pInput->startRowIndex; ++i) {
2,147,483,647✔
1172
        if (pCol->hasNull && colDataIsNull_f(pCol, i)) {
2,147,483,647✔
1173
          continue;
1,923,631,304✔
1174
        }
1175

1176
        numOfElem += 1;
2,147,483,647✔
1177
        pStdRes->count += 1;
2,147,483,647✔
1178
        double nr = (double)plist[i];
2,147,483,647✔
1179
        if (pStdRes->count == 1) {
2,147,483,647✔
1180
          pStdRes->dsum = nr;
8,912,718✔
1181
        } else {
1182
          double          s_kminusone = pStdRes->dsum;
2,147,483,647✔
1183
          volatile double diff = nr - s_kminusone;
2,147,483,647✔
1184
          pStdRes->dsum = s_kminusone + diff / (double)pStdRes->count;
2,147,483,647✔
1185
          pStdRes->quadraticDSum += diff * (nr - pStdRes->dsum);
2,147,483,647✔
1186
        }
1187
      }
1188

1189
      break;
35,795,080✔
1190
    }
1191

1192
    case TSDB_DATA_TYPE_BIGINT: {
40,241,093✔
1193
      int64_t* plist = (int64_t*)pCol->pData;
40,241,093✔
1194
      for (int32_t i = start; i < numOfRows + pInput->startRowIndex; ++i) {
2,147,483,647✔
1195
        if (pCol->hasNull && colDataIsNull_f(pCol, i)) {
2,147,483,647✔
1196
          continue;
2,147,483,647✔
1197
        }
1198

1199
        numOfElem += 1;
2,001,058,457✔
1200
        pStdRes->count += 1;
2,001,058,457✔
1201
        double nr = (double)plist[i];
2,019,570,117✔
1202
        if (pStdRes->count == 1) {
2,019,596,238✔
1203
          pStdRes->dsum = nr;
8,704,399✔
1204
        } else {
1205
          double          s_kminusone = pStdRes->dsum;
2,010,884,747✔
1206
          volatile double diff = nr - s_kminusone;
2,010,837,608✔
1207
          pStdRes->dsum = s_kminusone + diff / (double)pStdRes->count;
2,010,837,608✔
1208
          pStdRes->quadraticDSum += diff * (nr - pStdRes->dsum);
2,010,895,902✔
1209
        }
1210
      }
1211
      break;
40,242,050✔
1212
    }
1213

1214
    case TSDB_DATA_TYPE_UTINYINT: {
13,344,666✔
1215
      uint8_t* plist = (uint8_t*)pCol->pData;
13,344,666✔
1216
      for (int32_t i = start; i < numOfRows + start; ++i) {
2,147,483,647✔
1217
        if (pCol->hasNull && colDataIsNull_f(pCol, i)) {
2,147,483,647✔
1218
          continue;
2,147,483,647✔
1219
        }
1220

1221
        numOfElem += 1;
2,147,483,647✔
1222
        pStdRes->count += 1;
2,147,483,647✔
1223
        double nr = (double)plist[i];
2,147,483,647✔
1224
        if (pStdRes->count == 1) {
2,147,483,647✔
1225
          pStdRes->dsum = nr;
200,521✔
1226
        } else {
1227
          double          s_kminusone = pStdRes->dsum;
2,147,483,647✔
1228
          volatile double diff = nr - s_kminusone;
2,147,483,647✔
1229
          pStdRes->dsum = s_kminusone + diff / (double)pStdRes->count;
2,147,483,647✔
1230
          pStdRes->quadraticDSum += diff * (nr - pStdRes->dsum);
2,147,483,647✔
1231
        }
1232
      }
1233

1234
      break;
14,855,515✔
1235
    }
1236

1237
    case TSDB_DATA_TYPE_USMALLINT: {
10,730,000✔
1238
      uint16_t* plist = (uint16_t*)pCol->pData;
10,730,000✔
1239
      for (int32_t i = start; i < numOfRows + pInput->startRowIndex; ++i) {
2,147,483,647✔
1240
        if (pCol->hasNull && colDataIsNull_f(pCol, i)) {
2,147,483,647✔
1241
          continue;
2,147,483,647✔
1242
        }
1243

1244
        numOfElem += 1;
1,354,911,145✔
1245
        pStdRes->count += 1;
1,354,911,145✔
1246
        double nr = (double)plist[i];
1,369,371,961✔
1247
        if (pStdRes->count == 1) {
1,369,378,396✔
1248
          pStdRes->dsum = nr;
87,028✔
1249
        } else {
1250
          double          s_kminusone = pStdRes->dsum;
1,369,282,593✔
1251
          volatile double diff = nr - s_kminusone;
1,369,287,273✔
1252
          pStdRes->dsum = s_kminusone + diff / (double)pStdRes->count;
1,369,287,273✔
1253
          pStdRes->quadraticDSum += diff * (nr - pStdRes->dsum);
1,369,284,348✔
1254
        }
1255
      }
1256
      break;
10,729,415✔
1257
    }
1258

1259
    case TSDB_DATA_TYPE_UINT: {
5,851,845✔
1260
      uint32_t* plist = (uint32_t*)pCol->pData;
5,851,845✔
1261
      for (int32_t i = start; i < numOfRows + pInput->startRowIndex; ++i) {
2,147,483,647✔
1262
        if (pCol->hasNull && colDataIsNull_f(pCol, i)) {
2,147,483,647✔
1263
          continue;
2,032,402,380✔
1264
        }
1265

1266
        numOfElem += 1;
824,156,255✔
1267
        pStdRes->count += 1;
824,156,255✔
1268
        double nr = (double)plist[i];
829,907,360✔
1269
        if (pStdRes->count == 1) {
829,907,945✔
1270
          pStdRes->dsum = nr;
58,678✔
1271
        } else {
1272
          double          s_kminusone = pStdRes->dsum;
829,851,022✔
1273
          volatile double diff = nr - s_kminusone;
829,849,852✔
1274
          pStdRes->dsum = s_kminusone + diff / (double)pStdRes->count;
829,849,852✔
1275
          pStdRes->quadraticDSum += diff * (nr - pStdRes->dsum);
829,854,532✔
1276
        }
1277
      }
1278

1279
      break;
5,851,260✔
1280
    }
1281

1282
    case TSDB_DATA_TYPE_UBIGINT: {
5,850,904✔
1283
      uint64_t* plist = (uint64_t*)pCol->pData;
5,850,904✔
1284
      for (int32_t i = start; i < numOfRows + pInput->startRowIndex; ++i) {
2,147,483,647✔
1285
        if (pCol->hasNull && colDataIsNull_f(pCol, i)) {
2,147,483,647✔
1286
          continue;
2,147,483,647✔
1287
        }
1288

1289
        numOfElem += 1;
646,253,127✔
1290
        pStdRes->count += 1;
646,253,127✔
1291
        double nr = (double)plist[i];
649,830,195✔
1292
        if (pStdRes->count == 1) {
649,858,492✔
1293
          pStdRes->dsum = nr;
50,622✔
1294
        } else {
1295
          double          s_kminusone = pStdRes->dsum;
649,855,745✔
1296
          volatile double diff = nr - s_kminusone;
649,844,911✔
1297
          pStdRes->dsum = s_kminusone + diff / (double)pStdRes->count;
649,844,911✔
1298
          pStdRes->quadraticDSum += diff * (nr - pStdRes->dsum);
649,840,591✔
1299
        }
1300
      }
1301
      break;
5,851,489✔
1302
    }
1303

1304
    case TSDB_DATA_TYPE_FLOAT: {
9,744,435✔
1305
      float* plist = (float*)pCol->pData;
9,744,435✔
1306
      for (int32_t i = start; i < numOfRows + pInput->startRowIndex; ++i) {
1,696,424,508✔
1307
        if (pCol->hasNull && colDataIsNull_f(pCol, i)) {
1,686,679,959✔
1308
          continue;
6,811,516✔
1309
        }
1310

1311
        numOfElem += 1;
1,679,868,215✔
1312
        pStdRes->count += 1;
1,679,868,215✔
1313
        double nr = (double)plist[i];
1,679,868,785✔
1314
        if (pStdRes->count == 1) {
1,679,861,717✔
1315
          pStdRes->dsum = nr;
7,951,115✔
1316
        } else {
1317
          double          s_kminusone = pStdRes->dsum;
1,671,917,556✔
1318
          volatile double diff = nr - s_kminusone;
1,671,917,670✔
1319
          pStdRes->dsum = s_kminusone + diff / (double)pStdRes->count;
1,671,917,670✔
1320
          pStdRes->quadraticDSum += diff * (nr - pStdRes->dsum);
1,671,917,556✔
1321
        }
1322
      }
1323
      break;
9,744,435✔
1324
    }
1325

1326
    case TSDB_DATA_TYPE_DOUBLE: {
11,258,117✔
1327
      double* plist = (double*)pCol->pData;
11,258,117✔
1328
      for (int32_t i = start; i < numOfRows + pInput->startRowIndex; ++i) {
270,373,605✔
1329
        if (pCol->hasNull && colDataIsNull_f(pCol, i)) {
259,121,708✔
1330
          continue;
95,026,390✔
1331
        }
1332

1333
        numOfElem += 1;
164,075,714✔
1334
        pStdRes->count += 1;
164,075,714✔
1335
        double nr = (double)plist[i];
164,074,646✔
1336
        if (pStdRes->count == 1) {
164,074,638✔
1337
          pStdRes->dsum = nr;
2,229,851✔
1338
        } else {
1339
          double          s_kminusone = pStdRes->dsum;
161,850,453✔
1340
          volatile double diff = nr - s_kminusone;
161,791,923✔
1341
          pStdRes->dsum = s_kminusone + diff / (double)pStdRes->count;
161,791,923✔
1342
          pStdRes->quadraticDSum += diff * (nr - pStdRes->dsum);
161,845,767✔
1343
        }
1344
      }
1345
      break;
11,261,205✔
1346
    }
1347

UNCOV
1348
    default:
×
UNCOV
1349
      break;
×
1350
  }
1351

1352
_stddev_over:
1,080,002,914✔
1353
  // data in the check operation are all null, not output
1354
  SET_VAL(GET_RES_INFO(pCtx), numOfElem, 1);
1,080,002,914✔
1355
  return TSDB_CODE_SUCCESS;
1,078,757,134✔
1356
}
1357

1358
static void stdTransferInfo(SStdRes* pInput, SStdRes* pOutput) {
17,119,356✔
1359
  if (IS_NULL_TYPE(pInput->type)) {
17,119,356✔
1360
    return;
21,050✔
1361
  }
1362
  pOutput->type = pInput->type;
17,098,306✔
1363
  if (pOutput->count == 0) {
17,098,306✔
1364
    pOutput->quadraticDSum += pInput->quadraticDSum;
16,465,258✔
1365
    pOutput->dsum += pInput->dsum;
16,465,258✔
1366
    pOutput->count = pInput->count;
16,465,258✔
1367
  } else if (pInput->count > 0) {
633,048✔
1368
    double totalCount = pOutput->count + pInput->count;
251,440✔
1369
    double totalSum = pInput->count * pInput->dsum + pOutput->count * pOutput->dsum;
251,440✔
1370
    double mean = totalSum / totalCount;
251,440✔
1371

1372
    /*
1373
    pOutput->quadraticDSum += pInput->quadraticDSum + pInput->count * pInput->dsum * pInput->dsum +
1374
                              pOutput->count * pOutput->dsum * pOutput->dsum - totalSum * mean;
1375
    */
1376

1377
    double diff = pInput->dsum - pOutput->dsum;
251,440✔
1378
    pOutput->quadraticDSum += pInput->quadraticDSum + pInput->count * pOutput->count * (diff * diff) / totalCount;
251,440✔
1379
    pOutput->dsum = mean;
251,440✔
1380
    pOutput->count += pInput->count;
251,440✔
1381
  }
1382
}
1383

1384
int32_t stdFunctionMerge(SqlFunctionCtx* pCtx) {
17,108,610✔
1385
  SInputColumnInfoData* pInput = &pCtx->input;
17,108,610✔
1386
  SColumnInfoData*      pCol = pInput->pData[0];
17,108,610✔
1387

1388
  if (IS_NULL_TYPE(pCol->info.type)) {
17,108,610✔
UNCOV
1389
    SET_VAL(GET_RES_INFO(pCtx), 0, 1);
×
UNCOV
1390
    return TSDB_CODE_SUCCESS;
×
1391
  }
1392

1393
  if (pCol->info.type != TSDB_DATA_TYPE_BINARY) {
17,108,610✔
UNCOV
1394
    return TSDB_CODE_FUNC_FUNTION_PARA_TYPE;
×
1395
  }
1396

1397
  SStdRes* pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
17,108,610✔
1398

1399
  for (int32_t i = pInput->startRowIndex; i < pInput->startRowIndex + pInput->numOfRows; ++i) {
34,227,966✔
1400
    if (colDataIsNull_s(pCol, i)) continue;
34,238,712✔
1401
    char*    data = colDataGetData(pCol, i);
17,119,356✔
1402
    SStdRes* pInputInfo = (SStdRes*)varDataVal(data);
17,119,356✔
1403
    stdTransferInfo(pInputInfo, pInfo);
17,119,356✔
1404
  }
1405

1406
  SET_VAL(GET_RES_INFO(pCtx), 1, 1);
17,108,610✔
1407
  return TSDB_CODE_SUCCESS;
17,108,610✔
1408
}
1409

1410
int32_t stddevFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
694,013,709✔
1411
  SInputColumnInfoData* pInput = &pCtx->input;
694,013,709✔
1412
  SStdRes*              pStddevRes = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
694,013,709✔
1413
  int32_t               type = pStddevRes->type;
694,013,709✔
1414
  double                avg;
1415

1416
  if (pStddevRes->count == 0) {
694,013,709✔
1417
    GET_RES_INFO(pCtx)->numOfRes = 0;
228,337,434✔
1418

1419
    return functionFinalize(pCtx, pBlock);
228,337,434✔
1420
  }
1421

1422
  if (pStddevRes->count == 1) {
465,676,275✔
1423
    pStddevRes->result = 0.0;
320,500,827✔
1424
  } else {
1425
    pStddevRes->result = sqrt(pStddevRes->quadraticDSum / pStddevRes->count);
145,175,448✔
1426
  }
1427

1428
  // check for overflow
1429
  if (isinf(pStddevRes->result) || isnan(pStddevRes->result)) {
465,676,275✔
UNCOV
1430
    GET_RES_INFO(pCtx)->numOfRes = 0;
×
1431
  }
1432

1433
  return functionFinalize(pCtx, pBlock);
465,675,322✔
1434
}
1435

1436
int32_t stdvarFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
6,370,915✔
1437
  SInputColumnInfoData* pInput = &pCtx->input;
6,370,915✔
1438
  SStdRes*              pStdvarRes = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
6,370,915✔
1439
  int32_t               type = pStdvarRes->type;
6,370,915✔
1440
  double                avg;
1441

1442
  if (pStdvarRes->count == 0) {
6,370,915✔
1443
    GET_RES_INFO(pCtx)->numOfRes = 0;
23,490✔
1444
    return functionFinalize(pCtx, pBlock);
23,490✔
1445
  }
1446

1447
  if (pStdvarRes->count == 1) {
6,347,425✔
1448
    pStdvarRes->result = 0.0;
876✔
1449
  } else {
1450
    pStdvarRes->result = pStdvarRes->quadraticDSum / pStdvarRes->count;
6,346,549✔
1451
  }
1452

1453
  // check for overflow
1454
  if (isinf(pStdvarRes->result) || isnan(pStdvarRes->result)) {
6,347,425✔
UNCOV
1455
    GET_RES_INFO(pCtx)->numOfRes = 0;
×
1456
  }
1457

1458
  return functionFinalize(pCtx, pBlock);
6,347,425✔
1459
}
1460

1461
int32_t stdPartialFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
17,122,431✔
1462
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
17,122,431✔
1463
  SStdRes*             pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
17,122,431✔
1464
  int32_t              resultBytes = getStdInfoSize();
17,122,776✔
1465
  char*                res = taosMemoryCalloc(resultBytes + VARSTR_HEADER_SIZE, sizeof(char));
17,121,945✔
1466

1467
  if (NULL == res) {
17,122,431✔
UNCOV
1468
    return terrno;
×
1469
  }
1470
  (void)memcpy(varDataVal(res), pInfo, resultBytes);
17,122,431✔
1471
  varDataSetLen(res, resultBytes);
17,122,431✔
1472

1473
  int32_t          slotId = pCtx->pExpr->base.resSchema.slotId;
17,122,431✔
1474
  SColumnInfoData* pCol = taosArrayGet(pBlock->pDataBlock, slotId);
17,122,776✔
1475
  if (NULL == pCol) {
17,122,086✔
UNCOV
1476
    taosMemoryFree(res);
×
UNCOV
1477
    return TSDB_CODE_OUT_OF_RANGE;
×
1478
  }
1479

1480
  int32_t code = colDataSetVal(pCol, pBlock->info.rows, res, false);
17,122,086✔
1481

1482
  taosMemoryFree(res);
17,122,431✔
1483
  return code;
17,122,776✔
1484
}
1485

1486
int32_t stdCombine(SqlFunctionCtx* pDestCtx, SqlFunctionCtx* pSourceCtx) {
×
UNCOV
1487
  SResultRowEntryInfo* pDResInfo = GET_RES_INFO(pDestCtx);
×
1488
  SStdRes*             pDBuf = GET_ROWCELL_INTERBUF(pDResInfo);
×
1489

1490
  SResultRowEntryInfo* pSResInfo = GET_RES_INFO(pSourceCtx);
×
UNCOV
1491
  SStdRes*             pSBuf = GET_ROWCELL_INTERBUF(pSResInfo);
×
1492
  int16_t              type = pDBuf->type == TSDB_DATA_TYPE_NULL ? pSBuf->type : pDBuf->type;
×
1493

1494
  stdTransferInfo(pSBuf, pDBuf);
×
1495

1496
  pDResInfo->numOfRes = TMAX(pDResInfo->numOfRes, pSResInfo->numOfRes);
×
UNCOV
1497
  pDResInfo->isNullRes &= pSResInfo->isNullRes;
×
UNCOV
1498
  return TSDB_CODE_SUCCESS;
×
1499
}
1500

1501
int32_t stddevsampFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
3,055,503✔
1502
  SInputColumnInfoData* pInput = &pCtx->input;
3,055,503✔
1503
  SStdRes*              pStddevRes = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
3,055,503✔
1504
  double                avg;
1505

1506
  if (pStddevRes->count == 0) {
3,055,503✔
1507
    GET_RES_INFO(pCtx)->numOfRes = 0;
438✔
1508
    return functionFinalize(pCtx, pBlock);
438✔
1509
  }
1510

1511
  if (pStddevRes->count == 1) {
3,055,065✔
1512
    pStddevRes->result = 0.0;
438✔
1513
  } else {
1514
    pStddevRes->result = sqrt(pStddevRes->quadraticDSum / (pStddevRes->count - 1));
3,054,627✔
1515
  }
1516

1517
  // check for overflow
1518
  if (isinf(pStddevRes->result) || isnan(pStddevRes->result)) {
3,055,065✔
UNCOV
1519
    GET_RES_INFO(pCtx)->numOfRes = 0;
×
1520
  }
1521

1522
  return functionFinalize(pCtx, pBlock);
3,055,065✔
1523
}
1524

1525
int32_t stdvarsampFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
3,054,627✔
1526
  SInputColumnInfoData* pInput = &pCtx->input;
3,054,627✔
1527
  SStdRes*              pStddevRes = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
3,054,627✔
1528
  double                avg;
1529

1530
  if (pStddevRes->count == 0) {
3,054,627✔
1531
    GET_RES_INFO(pCtx)->numOfRes = 0;
438✔
1532
    return functionFinalize(pCtx, pBlock);
438✔
1533
  }
1534

1535
  if (pStddevRes->count == 1) {
3,054,189✔
1536
    pStddevRes->result = 0.0;
438✔
1537
  } else {
1538
    pStddevRes->result = pStddevRes->quadraticDSum / (pStddevRes->count - 1);
3,053,751✔
1539
  }
1540

1541
  // check for overflow
1542
  if (isinf(pStddevRes->result) || isnan(pStddevRes->result)) {
3,054,189✔
UNCOV
1543
    GET_RES_INFO(pCtx)->numOfRes = 0;
×
1544
  }
1545

1546
  return functionFinalize(pCtx, pBlock);
3,054,189✔
1547
}
1548

1549
bool gconcatGetFuncEnv(SFunctionNode* pFunc, SFuncExecEnv* pEnv) {
1,361✔
1550
  pEnv->calcMemSize = sizeof(SGconcatRes);
1,361✔
1551
  return true;
1,361✔
1552
}
1553

1554
int32_t gconcatFunctionSetup(SqlFunctionCtx* pCtx, SResultRowEntryInfo* pResultInfo) {
1,361✔
1555
  if (pResultInfo->initialized) {
1,361✔
UNCOV
1556
    return TSDB_CODE_SUCCESS;
×
1557
  }
1558
  if (TSDB_CODE_SUCCESS != functionSetup(pCtx, pResultInfo)) {
1,361✔
UNCOV
1559
    return TSDB_CODE_FUNC_SETUP_ERROR;
×
1560
  }
1561

1562
  SGconcatRes* pRes = GET_ROWCELL_INTERBUF(pResultInfo);
1,361✔
1563
  (void)memset(pRes, 0, sizeof(SGconcatRes));
1,361✔
1564

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

1567
  int32_t sepParamIdx = pCtx->numOfParams - 1;
1,361✔
1568
  pRes->separator = pCtx->param[sepParamIdx].param.pz;
1,361✔
1569
  pRes->type = pCtx->param[sepParamIdx].param.nType;
1,361✔
1570

1571
  /*
1572
  SInputColumnInfoData* pInput = &pCtx->input;
1573
  int32_t               type = pInput->pData[0]->info.type;
1574

1575
  pRes->nchar = (type == TSDB_DATA_TYPE_NCHAR);
1576
  */
1577

1578
  return TSDB_CODE_SUCCESS;
1,361✔
1579
}
1580

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

1603
  return TSDB_CODE_SUCCESS;
17,233✔
1604
}
1605

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

1618
  if (!pRes->result) {
907✔
1619
    pRes->result = taosMemoryCalloc(1, TSDB_MAX_FIELD_LEN);
907✔
1620
    if (!pRes->result) {
907✔
UNCOV
1621
      return terrno;
×
1622
    }
1623

1624
    varDataSetLen(pRes->result, 0);
907✔
1625

1626
    for (int c = 0; c < numOfCols - 1; ++c) {
1,814✔
1627
      SColumnInfoData* pCol = pInput->pData[c];
907✔
1628
      int32_t          type = pCol->info.type;
907✔
1629

1630
      if (TSDB_DATA_TYPE_NCHAR == type) {
907✔
UNCOV
1631
        pRes->nchar = true;
×
1632
      }
1633
    }
1634
  } else {
1635
    dataLen = varDataLen(pRes->result);
×
1636

UNCOV
1637
    prefixSep = true;
×
1638
    /*
1639
    code = gconcatHelper(sep, pRes->result, hasNchar, pRes->type, &dataLen, NULL);
1640
    if (code) {
1641
      goto _over;
1642
    }
1643
    */
1644
  }
1645

1646
  // computing based on the true data block
1647
  char*            buf = pRes->result;
907✔
1648
  SColumnInfoData* pCol = pInput->pData[numOfCols - 1];
907✔
1649

1650
  sep = colDataGetData(pCol, 0);
907✔
1651
  pRes->type = pCol->info.type;
907✔
1652
  for (int r = rowStart; r < rowStart + numOfRows; ++r) {
9,977✔
1653
    if (prefixSep) {
9,070✔
1654
      // concat the separator
1655
      // setup sepatator's charset instead of the default: pRes->charsetCxt
1656

1657
      code = gconcatHelper(sep, buf, hasNchar, pRes->type, &dataLen, NULL);
8,163✔
1658
      if (code) {
8,163✔
UNCOV
1659
        goto _over;
×
1660
      }
1661
    }
1662

1663
    for (int c = 0; c < numOfCols - 1; ++c) {
18,140✔
1664
      SColumnInfoData* pCol = pInput->pData[c];
9,070✔
1665
      int32_t          type = pCol->info.type;
9,070✔
1666

1667
      if (IS_NULL_TYPE(type) || (pCol->hasNull && colDataIsNull_f(pCol, r))) {
9,070✔
UNCOV
1668
        continue;
×
1669
      }
1670

1671
      // concat this row's all columns
1672
      code = gconcatHelper(colDataGetData(pCol, r), buf, hasNchar, pInput->pData[c]->info.type, &dataLen, NULL);
9,070✔
1673
      if (code) {
9,070✔
UNCOV
1674
        goto _over;
×
1675
      }
1676
    }
1677

1678
    prefixSep = true;
9,070✔
1679
  }
1680

1681
  varDataSetLen(buf, dataLen);
907✔
1682
  numOfElem += 1;
907✔
1683

1684
_over:
907✔
1685
  // data in the check operation are all null, not output
1686
  SET_VAL(GET_RES_INFO(pCtx), numOfElem, 1);
907✔
1687
  return code;
907✔
1688
}
1689

1690
int32_t gconcatFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
907✔
1691
  int32_t               code = 0;
907✔
1692
  SInputColumnInfoData* pInput = &pCtx->input;
907✔
1693
  SGconcatRes*          pRes = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
907✔
1694
  int32_t               slotId = pCtx->pExpr->base.resSchema.slotId;
907✔
1695
  SColumnInfoData*      pCol = taosArrayGet(pBlock->pDataBlock, slotId);
907✔
1696

1697
  if (NULL == pCol) {
907✔
UNCOV
1698
    taosMemoryFree(pRes->result);
×
UNCOV
1699
    return TSDB_CODE_OUT_OF_RANGE;
×
1700
  }
1701

1702
  code = colDataSetVal(pCol, pBlock->info.rows, pRes->result, NULL == pRes->result);
907✔
1703

1704
  taosMemoryFree(pRes->result);
907✔
1705

1706
  return code;
907✔
1707
}
1708

1709
bool getLeastSQRFuncEnv(SFunctionNode* pFunc, SFuncExecEnv* pEnv) {
1,061,907✔
1710
  pEnv->calcMemSize = sizeof(SLeastSQRInfo);
1,061,907✔
1711
  return true;
1,062,421✔
1712
}
1713

1714
int32_t leastSQRFunctionSetup(SqlFunctionCtx* pCtx, SResultRowEntryInfo* pResultInfo) {
4,901,082✔
1715
  if (pResultInfo->initialized) {
4,901,082✔
UNCOV
1716
    return TSDB_CODE_SUCCESS;
×
1717
  }
1718
  if (TSDB_CODE_SUCCESS != functionSetup(pCtx, pResultInfo)) {
4,901,596✔
UNCOV
1719
    return TSDB_CODE_FUNC_SETUP_ERROR;
×
1720
  }
1721

1722
  SLeastSQRInfo* pInfo = GET_ROWCELL_INTERBUF(pResultInfo);
4,902,624✔
1723

1724
  GET_TYPED_DATA(pInfo->startVal, double, pCtx->param[1].param.nType, &pCtx->param[1].param.i,
4,902,624✔
1725
                 typeGetTypeModFromCol(pCtx->param[1].pCol));
1726
  GET_TYPED_DATA(pInfo->stepVal, double, pCtx->param[2].param.nType, &pCtx->param[2].param.i,
4,901,596✔
1727
                 typeGetTypeModFromCol(pCtx->param[2].pCol));
1728
  return TSDB_CODE_SUCCESS;
4,901,082✔
1729
}
1730

1731
int32_t leastSQRFunction(SqlFunctionCtx* pCtx) {
5,834,029✔
1732
  int32_t numOfElem = 0;
5,834,029✔
1733

1734
  SInputColumnInfoData* pInput = &pCtx->input;
5,834,029✔
1735
  int32_t               type = pInput->pData[0]->info.type;
5,834,543✔
1736

1737
  SLeastSQRInfo* pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
5,835,571✔
1738

1739
  SColumnInfoData* pCol = pInput->pData[0];
5,834,029✔
1740

1741
  double(*param)[3] = pInfo->matrix;
5,833,515✔
1742
  double x = pInfo->startVal;
5,835,057✔
1743

1744
  int32_t start = pInput->startRowIndex;
5,834,543✔
1745
  int32_t numOfRows = pInput->numOfRows;
5,834,029✔
1746

1747
  switch (type) {
5,833,515✔
1748
    case TSDB_DATA_TYPE_TINYINT: {
2,446,738✔
1749
      int8_t* plist = (int8_t*)pCol->pData;
2,446,738✔
1750
      for (int32_t i = start; i < numOfRows + pInput->startRowIndex; ++i) {
95,566,028✔
1751
        if (pCol->hasNull && colDataIsNull_f(pCol, i)) {
93,123,916✔
1752
          continue;
75,916,488✔
1753
        }
1754
        numOfElem++;
17,181,928✔
1755
        LEASTSQR_CAL(param, x, plist, i, pInfo->stepVal);
17,181,928✔
1756
      }
1757
      break;
2,448,794✔
1758
    }
1759
    case TSDB_DATA_TYPE_SMALLINT: {
786,489✔
1760
      int16_t* plist = (int16_t*)pCol->pData;
786,489✔
1761
      for (int32_t i = start; i < numOfRows + pInput->startRowIndex; ++i) {
89,194,681✔
1762
        if (pCol->hasNull && colDataIsNull_f(pCol, i)) {
88,408,192✔
1763
          continue;
302,044✔
1764
        }
1765

1766
        numOfElem++;
88,102,522✔
1767
        LEASTSQR_CAL(param, x, plist, i, pInfo->stepVal);
88,102,522✔
1768
      }
1769
      break;
786,489✔
1770
    }
1771

1772
    case TSDB_DATA_TYPE_INT: {
597,834✔
1773
      int32_t* plist = (int32_t*)pCol->pData;
597,834✔
1774
      for (int32_t i = start; i < numOfRows + pInput->startRowIndex; ++i) {
89,078,083✔
1775
        if (pCol->hasNull && colDataIsNull_f(pCol, i)) {
88,480,249✔
1776
          continue;
420,842✔
1777
        }
1778

1779
        numOfElem++;
88,059,407✔
1780
        LEASTSQR_CAL(param, x, plist, i, pInfo->stepVal);
88,059,407✔
1781
      }
1782
      break;
597,834✔
1783
    }
1784

1785
    case TSDB_DATA_TYPE_BIGINT: {
365,735✔
1786
      int64_t* plist = (int64_t*)pCol->pData;
365,735✔
1787
      for (int32_t i = start; i < numOfRows + pInput->startRowIndex; ++i) {
17,926,679✔
1788
        if (pCol->hasNull && colDataIsNull_f(pCol, i)) {
17,560,944✔
1789
          continue;
204,844✔
1790
        }
1791

1792
        numOfElem++;
17,356,100✔
1793
        LEASTSQR_CAL(param, x, plist, i, pInfo->stepVal);
17,356,100✔
1794
      }
1795
      break;
365,735✔
1796
    }
1797

1798
    case TSDB_DATA_TYPE_UTINYINT: {
16,498✔
1799
      uint8_t* plist = (uint8_t*)pCol->pData;
16,498✔
1800
      for (int32_t i = start; i < numOfRows + pInput->startRowIndex; ++i) {
17,173,206✔
1801
        if (pCol->hasNull && colDataIsNull_f(pCol, i)) {
17,156,708✔
1802
          continue;
9,614✔
1803
        }
1804
        numOfElem++;
17,147,094✔
1805
        LEASTSQR_CAL(param, x, plist, i, pInfo->stepVal);
17,147,094✔
1806
      }
1807
      break;
16,498✔
1808
    }
1809
    case TSDB_DATA_TYPE_USMALLINT: {
16,498✔
1810
      uint16_t* plist = (uint16_t*)pCol->pData;
16,498✔
1811
      for (int32_t i = start; i < numOfRows + pInput->startRowIndex; ++i) {
17,173,206✔
1812
        if (pCol->hasNull && colDataIsNull_f(pCol, i)) {
17,156,708✔
1813
          continue;
8,740✔
1814
        }
1815

1816
        numOfElem++;
17,147,968✔
1817
        LEASTSQR_CAL(param, x, plist, i, pInfo->stepVal);
17,147,968✔
1818
      }
1819
      break;
16,498✔
1820
    }
1821

1822
    case TSDB_DATA_TYPE_UINT: {
16,498✔
1823
      uint32_t* plist = (uint32_t*)pCol->pData;
16,498✔
1824
      for (int32_t i = start; i < numOfRows + pInput->startRowIndex; ++i) {
17,173,206✔
1825
        if (pCol->hasNull && colDataIsNull_f(pCol, i)) {
17,156,708✔
1826
          continue;
8,740✔
1827
        }
1828

1829
        numOfElem++;
17,147,968✔
1830
        LEASTSQR_CAL(param, x, plist, i, pInfo->stepVal);
17,147,968✔
1831
      }
1832
      break;
16,498✔
1833
    }
1834

1835
    case TSDB_DATA_TYPE_UBIGINT: {
16,498✔
1836
      uint64_t* plist = (uint64_t*)pCol->pData;
16,498✔
1837
      for (int32_t i = start; i < numOfRows + pInput->startRowIndex; ++i) {
17,173,206✔
1838
        if (pCol->hasNull && colDataIsNull_f(pCol, i)) {
17,156,708✔
1839
          continue;
8,740✔
1840
        }
1841

1842
        numOfElem++;
17,147,968✔
1843
        LEASTSQR_CAL(param, x, plist, i, pInfo->stepVal);
17,147,968✔
1844
      }
1845
      break;
16,498✔
1846
    }
1847

1848
    case TSDB_DATA_TYPE_FLOAT: {
1,163,955✔
1849
      float* plist = (float*)pCol->pData;
1,163,955✔
1850
      for (int32_t i = start; i < numOfRows + pInput->startRowIndex; ++i) {
19,470,563✔
1851
        if (pCol->hasNull && colDataIsNull_f(pCol, i)) {
18,306,608✔
1852
          continue;
403,144✔
1853
        }
1854

1855
        numOfElem++;
17,903,464✔
1856
        LEASTSQR_CAL(param, x, plist, i, pInfo->stepVal);
17,903,464✔
1857
      }
1858
      break;
1,163,955✔
1859
    }
1860

1861
    case TSDB_DATA_TYPE_DOUBLE: {
406,772✔
1862
      double* plist = (double*)pCol->pData;
406,772✔
1863
      for (int32_t i = start; i < numOfRows + pInput->startRowIndex; ++i) {
18,379,436✔
1864
        if (pCol->hasNull && colDataIsNull_f(pCol, i)) {
17,972,664✔
1865
          continue;
154,944✔
1866
        }
1867

1868
        numOfElem++;
17,817,720✔
1869
        LEASTSQR_CAL(param, x, plist, i, pInfo->stepVal);
17,817,720✔
1870
      }
1871
      break;
406,772✔
1872
    }
1873
    case TSDB_DATA_TYPE_NULL: {
×
1874
      GET_RES_INFO(pCtx)->isNullRes = 1;
×
UNCOV
1875
      numOfElem = 1;
×
UNCOV
1876
      break;
×
1877
    }
1878

UNCOV
1879
    default:
×
UNCOV
1880
      break;
×
1881
  }
1882

1883
  pInfo->startVal = x;
5,835,571✔
1884
  pInfo->num += numOfElem;
5,834,029✔
1885

1886
  SET_VAL(GET_RES_INFO(pCtx), numOfElem, 1);
5,834,543✔
1887

1888
  return TSDB_CODE_SUCCESS;
5,833,515✔
1889
}
1890

1891
int32_t leastSQRFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
4,900,720✔
1892
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
4,900,720✔
1893
  SLeastSQRInfo*       pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
4,901,234✔
1894
  int32_t              slotId = pCtx->pExpr->base.resSchema.slotId;
4,900,720✔
1895
  SColumnInfoData*     pCol = taosArrayGet(pBlock->pDataBlock, slotId);
4,900,720✔
1896

1897
  if (NULL == pCol) {
4,900,202✔
UNCOV
1898
    return TSDB_CODE_OUT_OF_RANGE;
×
1899
  }
1900
  int32_t currentRow = pBlock->info.rows;
4,900,202✔
1901

1902
  if (0 == pInfo->num) {
4,901,752✔
1903
    colDataSetNULL(pCol, currentRow);
3,637,016✔
1904
    return TSDB_CODE_SUCCESS;
3,637,016✔
1905
  }
1906

1907
  double(*param)[3] = pInfo->matrix;
1,264,218✔
1908

1909
  param[1][1] = (double)pInfo->num;
1,264,218✔
1910
  param[1][0] = param[0][1];
1,264,218✔
1911

1912
  double param00 = param[0][0] - param[1][0] * (param[0][1] / param[1][1]);
1,264,218✔
1913
  double param02 = param[0][2] - param[1][2] * (param[0][1] / param[1][1]);
1,264,218✔
1914

1915
  if (0 == param00) {
1,264,218✔
1916
    colDataSetNULL(pCol, currentRow);
636,639✔
1917
    return TSDB_CODE_SUCCESS;
636,639✔
1918
  }
1919

1920
  // param[0][1] = 0;
1921
  double param12 = param[1][2] - param02 * (param[1][0] / param00);
627,579✔
1922
  // param[1][0] = 0;
1923
  param02 /= param00;
628,097✔
1924

1925
  param12 /= param[1][1];
628,097✔
1926

1927
  char buf[LEASTSQUARES_BUFF_LENGTH] = {0};
628,097✔
1928
  char slopBuf[64] = {0};
628,097✔
1929
  char interceptBuf[64] = {0};
627,579✔
1930
  int  n = tsnprintf(slopBuf, 64, "%.6lf", param02);
627,579✔
1931
  if (n > LEASTSQUARES_DOUBLE_ITEM_LENGTH) {
627,579✔
1932
    (void)snprintf(slopBuf, 64, "%." DOUBLE_PRECISION_DIGITS, param02);
9,357✔
1933
  }
1934
  n = tsnprintf(interceptBuf, 64, "%.6lf", param12);
627,579✔
1935
  if (n > LEASTSQUARES_DOUBLE_ITEM_LENGTH) {
627,579✔
1936
    (void)snprintf(interceptBuf, 64, "%." DOUBLE_PRECISION_DIGITS, param12);
10,231✔
1937
  }
1938
  size_t len =
627,579✔
1939
      snprintf(varDataVal(buf), sizeof(buf) - VARSTR_HEADER_SIZE, "{slop:%s, intercept:%s}", slopBuf, interceptBuf);
627,579✔
1940
  varDataSetLen(buf, len);
627,579✔
1941

1942
  int32_t code = colDataSetVal(pCol, currentRow, buf, pResInfo->isNullRes);
628,097✔
1943

1944
  return code;
628,097✔
1945
}
1946

1947
int32_t leastSQRCombine(SqlFunctionCtx* pDestCtx, SqlFunctionCtx* pSourceCtx) {
×
1948
  SResultRowEntryInfo* pDResInfo = GET_RES_INFO(pDestCtx);
×
1949
  SLeastSQRInfo*       pDBuf = GET_ROWCELL_INTERBUF(pDResInfo);
×
UNCOV
1950
  int32_t              type = pDestCtx->input.pData[0]->info.type;
×
1951
  double(*pDparam)[3] = pDBuf->matrix;
×
1952

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

1969
bool getPercentileFuncEnv(SFunctionNode* pFunc, SFuncExecEnv* pEnv) {
86,432✔
1970
  pEnv->calcMemSize = sizeof(SPercentileInfo);
86,432✔
1971
  return true;
86,432✔
1972
}
1973

1974
int32_t percentileFunctionSetup(SqlFunctionCtx* pCtx, SResultRowEntryInfo* pResultInfo) {
589,110✔
1975
  if (pResultInfo->initialized) {
589,110✔
UNCOV
1976
    return TSDB_CODE_SUCCESS;
×
1977
  }
1978
  if (TSDB_CODE_SUCCESS != functionSetup(pCtx, pResultInfo)) {
589,110✔
UNCOV
1979
    return TSDB_CODE_FUNC_SETUP_ERROR;
×
1980
  }
1981

1982
  // in the first round, get the min-max value of all involved data
1983
  SPercentileInfo* pInfo = GET_ROWCELL_INTERBUF(pResultInfo);
589,110✔
1984
  SET_DOUBLE_VAL(&pInfo->minval, DBL_MAX);
589,110✔
1985
  SET_DOUBLE_VAL(&pInfo->maxval, -DBL_MAX);
589,110✔
1986
  pInfo->numOfElems = 0;
589,110✔
1987

1988
  return TSDB_CODE_SUCCESS;
589,110✔
1989
}
1990

1991
void percentileFunctionCleanupExt(SqlFunctionCtx* pCtx) {
86,868✔
1992
  if (pCtx == NULL || GET_RES_INFO(pCtx) == NULL || GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx)) == NULL) {
86,868✔
UNCOV
1993
    return;
×
1994
  }
1995
  SPercentileInfo* pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
86,868✔
1996
  if (pInfo->pMemBucket != NULL) {
86,868✔
1997
    tMemBucketDestroy(&(pInfo->pMemBucket));
436✔
1998
    pInfo->pMemBucket = NULL;
436✔
1999
  }
2000
}
2001

2002
int32_t percentileFunction(SqlFunctionCtx* pCtx) {
2,182,860✔
2003
  int32_t              code = TSDB_CODE_SUCCESS;
2,182,860✔
2004
  int32_t              numOfElems = 0;
2,182,860✔
2005
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
2,182,860✔
2006

2007
  SInputColumnInfoData* pInput = &pCtx->input;
2,182,860✔
2008
  SColumnDataAgg*       pAgg = pInput->pColumnDataAgg[0];
2,182,860✔
2009

2010
  SColumnInfoData* pCol = pInput->pData[0];
2,182,860✔
2011
  int32_t          type = pCol->info.type;
2,182,860✔
2012

2013
  SPercentileInfo* pInfo = GET_ROWCELL_INTERBUF(pResInfo);
2,182,860✔
2014
  if (pCtx->scanFlag == MAIN_SCAN && pInfo->stage == 0) {
2,182,860✔
2015
    pInfo->stage += 1;
589,110✔
2016

2017
    // all data are null, set it completed
2018
    if (pInfo->numOfElems == 0) {
589,110✔
2019
      pResInfo->complete = true;
348,499✔
2020
      return TSDB_CODE_SUCCESS;
348,499✔
2021
    } else {
2022
      code = tMemBucketCreate(pCol->info.bytes, type, typeGetTypeModFromColInfo(&pCol->info), pInfo->minval,
240,611✔
2023
                              pInfo->maxval, pCtx->hasWindowOrGroup, &pInfo->pMemBucket, pInfo->numOfElems);
240,611✔
2024
      if (TSDB_CODE_SUCCESS != code) {
240,611✔
UNCOV
2025
        return code;
×
2026
      }
2027
    }
2028
  }
2029

2030
  // the first stage, only acquire the min/max value
2031
  if (pInfo->stage == 0) {
1,834,361✔
2032
    if (pCtx->input.colDataSMAIsSet) {
1,091,430✔
2033
      double tmin = 0.0, tmax = 0.0;
×
2034
      if (IS_SIGNED_NUMERIC_TYPE(type)) {
×
2035
        tmin = (double)GET_INT64_VAL(&pAgg->min);
×
2036
        tmax = (double)GET_INT64_VAL(&pAgg->max);
×
2037
      } else if (IS_FLOAT_TYPE(type)) {
×
2038
        tmin = GET_DOUBLE_VAL(&pAgg->min);
×
2039
        tmax = GET_DOUBLE_VAL(&pAgg->max);
×
2040
      } else if (IS_UNSIGNED_NUMERIC_TYPE(type)) {
×
UNCOV
2041
        tmin = (double)GET_UINT64_VAL(&pAgg->min);
×
UNCOV
2042
        tmax = (double)GET_UINT64_VAL(&pAgg->max);
×
2043
      }
2044

UNCOV
2045
      if (GET_DOUBLE_VAL(&pInfo->minval) > tmin) {
×
UNCOV
2046
        SET_DOUBLE_VAL(&pInfo->minval, tmin);
×
2047
      }
2048

UNCOV
2049
      if (GET_DOUBLE_VAL(&pInfo->maxval) < tmax) {
×
UNCOV
2050
        SET_DOUBLE_VAL(&pInfo->maxval, tmax);
×
2051
      }
2052

UNCOV
2053
      pInfo->numOfElems += (pInput->numOfRows - pAgg->numOfNull);
×
2054
    } else {
2055
      // check the valid data one by one
2056
      int32_t start = pInput->startRowIndex;
1,091,430✔
2057
      for (int32_t i = start; i < pInput->numOfRows + start; ++i) {
17,155,969✔
2058
        if (colDataIsNull_f(pCol, i)) {
16,064,539✔
2059
          continue;
426,676✔
2060
        }
2061

2062
        char* data = colDataGetData(pCol, i);
15,637,863✔
2063

2064
        double v = 0;
15,637,863✔
2065
        GET_TYPED_DATA(v, double, type, data, typeGetTypeModFromColInfo(&pCol->info));
15,637,863✔
2066
        if (v < GET_DOUBLE_VAL(&pInfo->minval)) {
15,637,863✔
2067
          SET_DOUBLE_VAL(&pInfo->minval, v);
265,409✔
2068
        }
2069

2070
        if (v > GET_DOUBLE_VAL(&pInfo->maxval)) {
15,637,863✔
2071
          SET_DOUBLE_VAL(&pInfo->maxval, v);
12,527,063✔
2072
        }
2073

2074
        pInfo->numOfElems += 1;
15,637,863✔
2075
      }
2076
    }
2077
  } else {
2078
    // the second stage, calculate the true percentile value
2079
    int32_t start = pInput->startRowIndex;
742,931✔
2080
    for (int32_t i = start; i < pInput->numOfRows + start; ++i) {
16,354,634✔
2081
      if (colDataIsNull_f(pCol, i)) {
15,612,139✔
UNCOV
2082
        continue;
×
2083
      }
2084

2085
      char* data = colDataGetData(pCol, i);
15,612,139✔
2086
      numOfElems += 1;
15,612,139✔
2087
      code = tMemBucketPut(pInfo->pMemBucket, data, 1);
15,612,139✔
2088
      if (code != TSDB_CODE_SUCCESS) {
15,612,139✔
2089
        tMemBucketDestroy(&(pInfo->pMemBucket));
436✔
2090
        return code;
436✔
2091
      }
2092
    }
2093

2094
    SET_VAL(pResInfo, numOfElems, 1);
742,495✔
2095
  }
2096

2097
  pCtx->needCleanup = true;
1,833,925✔
2098
  return TSDB_CODE_SUCCESS;
1,833,925✔
2099
}
2100

2101
int32_t percentileFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
588,238✔
2102
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
588,238✔
2103
  SPercentileInfo*     ppInfo = (SPercentileInfo*)GET_ROWCELL_INTERBUF(pResInfo);
588,238✔
2104

2105
  int32_t code = 0;
588,238✔
2106
  double  v = 0;
588,238✔
2107

2108
  tMemBucket** pMemBucket = &ppInfo->pMemBucket;
588,238✔
2109
  if ((*pMemBucket) != NULL && (*pMemBucket)->total > 0) {  // check for null
588,238✔
2110
    if (pCtx->numOfParams > 2) {
239,739✔
2111
      char buf[3200] = {0};
2,616✔
2112
      // max length of double num is 317, e.g. use %.6lf to print -1.0e+308, consider the comma and bracket, 3200 is
2113
      // enough.
2114
      size_t len = 1;
2,616✔
2115

2116
      varDataVal(buf)[0] = '[';
2,616✔
2117
      for (int32_t i = 1; i < pCtx->numOfParams; ++i) {
28,776✔
2118
        SVariant* pVal = &pCtx->param[i].param;
26,160✔
2119

2120
        GET_TYPED_DATA(v, double, pVal->nType, &pVal->i, typeGetTypeModFromCol(pCtx->param[i].pCol));
26,160✔
2121

2122
        code = getPercentile((*pMemBucket), v, &ppInfo->result);
26,160✔
2123
        if (code != TSDB_CODE_SUCCESS) {
26,160✔
UNCOV
2124
          goto _fin_error;
×
2125
        }
2126

2127
        if (i == pCtx->numOfParams - 1) {
26,160✔
2128
          len += tsnprintf(varDataVal(buf) + len, sizeof(buf) - VARSTR_HEADER_SIZE - len, "%.6lf]", ppInfo->result);
2,616✔
2129
        } else {
2130
          len += tsnprintf(varDataVal(buf) + len, sizeof(buf) - VARSTR_HEADER_SIZE - len, "%.6lf, ", ppInfo->result);
23,544✔
2131
        }
2132
      }
2133

2134
      int32_t          slotId = pCtx->pExpr->base.resSchema.slotId;
2,616✔
2135
      SColumnInfoData* pCol = taosArrayGet(pBlock->pDataBlock, slotId);
2,616✔
2136
      if (NULL == pCol) {
2,616✔
UNCOV
2137
        code = terrno;
×
UNCOV
2138
        goto _fin_error;
×
2139
      }
2140

2141
      varDataSetLen(buf, len);
2,616✔
2142
      code = colDataSetVal(pCol, pBlock->info.rows, buf, false);
2,616✔
2143
      if (code != TSDB_CODE_SUCCESS) {
2,616✔
UNCOV
2144
        goto _fin_error;
×
2145
      }
2146

2147
      tMemBucketDestroy(pMemBucket);
2,616✔
2148
      return TSDB_CODE_SUCCESS;
2,616✔
2149
    } else {
2150
      SVariant* pVal = &pCtx->param[1].param;
237,123✔
2151

2152
      GET_TYPED_DATA(v, double, pVal->nType, &pVal->i, typeGetTypeModFromCol(pCtx->param[1].pCol));
237,123✔
2153

2154
      code = getPercentile((*pMemBucket), v, &ppInfo->result);
237,123✔
2155
      if (code != TSDB_CODE_SUCCESS) {
237,123✔
UNCOV
2156
        goto _fin_error;
×
2157
      }
2158

2159
      tMemBucketDestroy(pMemBucket);
237,123✔
2160
      return functionFinalize(pCtx, pBlock);
237,123✔
2161
    }
2162
  } else {
2163
    return functionFinalize(pCtx, pBlock);
348,499✔
2164
  }
2165

2166
_fin_error:
×
2167

UNCOV
2168
  tMemBucketDestroy(pMemBucket);
×
UNCOV
2169
  return code;
×
2170
}
2171

2172
bool getApercentileFuncEnv(SFunctionNode* pFunc, SFuncExecEnv* pEnv) {
3,287,264✔
2173
  int32_t bytesHist =
3,287,264✔
2174
      (int32_t)(sizeof(SAPercentileInfo) + sizeof(SHistogramInfo) + sizeof(SHistBin) * (MAX_HISTOGRAM_BIN + 1));
2175
  int32_t bytesDigest = (int32_t)(sizeof(SAPercentileInfo) + TDIGEST_SIZE(COMPRESSION));
3,287,264✔
2176
  pEnv->calcMemSize = TMAX(bytesHist, bytesDigest);
3,287,264✔
2177
  return true;
3,292,617✔
2178
}
2179

2180
int32_t getApercentileMaxSize() {
601,466✔
2181
  int32_t bytesHist =
601,466✔
2182
      (int32_t)(sizeof(SAPercentileInfo) + sizeof(SHistogramInfo) + sizeof(SHistBin) * (MAX_HISTOGRAM_BIN + 1));
2183
  int32_t bytesDigest = (int32_t)(sizeof(SAPercentileInfo) + TDIGEST_SIZE(COMPRESSION));
601,466✔
2184
  return TMAX(bytesHist, bytesDigest);
601,466✔
2185
}
2186

2187
static int8_t getApercentileAlgo(char* algoStr) {
2,888,392✔
2188
  int8_t algoType;
2189
  if (strcasecmp(algoStr, "default") == 0) {
2,888,392✔
2190
    algoType = APERCT_ALGO_DEFAULT;
1,442,638✔
2191
  } else if (strcasecmp(algoStr, "t-digest") == 0) {
1,445,754✔
2192
    algoType = APERCT_ALGO_TDIGEST;
1,446,782✔
2193
  } else {
UNCOV
2194
    algoType = APERCT_ALGO_UNKNOWN;
×
2195
  }
2196

2197
  return algoType;
2,888,392✔
2198
}
2199

2200
static void buildHistogramInfo(SAPercentileInfo* pInfo) {
134,116,743✔
2201
  pInfo->pHisto = (SHistogramInfo*)((char*)pInfo + sizeof(SAPercentileInfo));
134,116,743✔
2202
  pInfo->pHisto->elems = (SHistBin*)((char*)pInfo->pHisto + sizeof(SHistogramInfo));
134,118,803✔
2203
}
134,118,799✔
2204

2205
static void buildTDigestInfo(SAPercentileInfo* pInfo) {
2,904,002✔
2206
  pInfo->pTDigest = (TDigest*)((char*)pInfo + sizeof(SAPercentileInfo));
2,904,002✔
2207
}
2,907,090✔
2208

2209
int32_t apercentileFunctionSetup(SqlFunctionCtx* pCtx, SResultRowEntryInfo* pResultInfo) {
43,303,165✔
2210
  if (pResultInfo->initialized) {
43,303,165✔
UNCOV
2211
    return TSDB_CODE_SUCCESS;
×
2212
  }
2213
  if (TSDB_CODE_SUCCESS != functionSetup(pCtx, pResultInfo)) {
43,305,229✔
UNCOV
2214
    return TSDB_CODE_FUNC_SETUP_ERROR;
×
2215
  }
2216

2217
  SAPercentileInfo* pInfo = GET_ROWCELL_INTERBUF(pResultInfo);
43,305,229✔
2218

2219
  SVariant* pVal = &pCtx->param[1].param;
43,305,225✔
2220
  pInfo->percent = 0;
43,305,229✔
2221
  GET_TYPED_DATA(pInfo->percent, double, pVal->nType, &pVal->i, typeGetTypeModFromCol(pCtx->param[1].pCol));
43,304,197✔
2222

2223
  if (pCtx->numOfParams == 2) {
43,305,735✔
2224
    pInfo->algo = APERCT_ALGO_DEFAULT;
40,415,801✔
2225
  } else if (pCtx->numOfParams == 3) {
2,888,392✔
2226
    pInfo->algo = getApercentileAlgo(varDataVal(pCtx->param[2].param.pz));
2,888,906✔
2227
    if (pInfo->algo == APERCT_ALGO_UNKNOWN) {
2,889,416✔
UNCOV
2228
      return TSDB_CODE_FUNC_FUNTION_PARA_VALUE;
×
2229
    }
2230
  }
2231

2232
  char* tmp = (char*)pInfo + sizeof(SAPercentileInfo);
43,305,225✔
2233
  if (pInfo->algo == APERCT_ALGO_TDIGEST) {
43,305,739✔
2234
    pInfo->pTDigest = tdigestNewFrom(tmp, COMPRESSION);
1,446,268✔
2235
  } else {
2236
    buildHistogramInfo(pInfo);
41,857,925✔
2237
    pInfo->pHisto = tHistogramCreateFrom(tmp, MAX_HISTOGRAM_BIN);
41,857,411✔
2238
    qDebug("%s set up histogram, numOfElems:%" PRId64 ", numOfEntry:%d, pHisto:%p, elems:%p", __FUNCTION__,
41,859,989✔
2239
           pInfo->pHisto->numOfElems, pInfo->pHisto->numOfEntries, pInfo->pHisto, pInfo->pHisto->elems);
2240
  }
2241

2242
  return TSDB_CODE_SUCCESS;
43,305,229✔
2243
}
2244

2245
int32_t apercentileFunction(SqlFunctionCtx* pCtx) {
52,919,438✔
2246
  int32_t               numOfElems = 0;
52,919,438✔
2247
  SResultRowEntryInfo*  pResInfo = GET_RES_INFO(pCtx);
52,919,438✔
2248
  SInputColumnInfoData* pInput = &pCtx->input;
52,918,920✔
2249

2250
  SColumnInfoData* pCol = pInput->pData[0];
52,920,537✔
2251
  int32_t          type = pCol->info.type;
52,920,023✔
2252

2253
  SAPercentileInfo* pInfo = GET_ROWCELL_INTERBUF(pResInfo);
52,920,023✔
2254

2255
  int32_t start = pInput->startRowIndex;
52,918,914✔
2256
  if (pInfo->algo == APERCT_ALGO_TDIGEST) {
52,918,914✔
2257
    buildTDigestInfo(pInfo);
1,445,822✔
2258
    tdigestAutoFill(pInfo->pTDigest, COMPRESSION);
1,445,304✔
2259
    for (int32_t i = start; i < pInput->numOfRows + start; ++i) {
75,394,792✔
2260
      if (colDataIsNull_f(pCol, i)) {
73,952,576✔
2261
        continue;
37,808,270✔
2262
      }
2263
      numOfElems += 1;
36,145,844✔
2264
      char* data = colDataGetData(pCol, i);
36,145,844✔
2265

2266
      double  v = 0;  // value
36,151,024✔
2267
      int64_t w = 1;  // weigth
36,151,024✔
2268
      GET_TYPED_DATA(v, double, type, data, typeGetTypeModFromColInfo(&pCol->info));
36,151,024✔
2269
      int32_t code = tdigestAdd(pInfo->pTDigest, v, w);
36,149,470✔
2270
      if (code != TSDB_CODE_SUCCESS) {
36,140,700✔
UNCOV
2271
        return code;
×
2272
      }
2273
    }
2274
  } else {
2275
    // might be a race condition here that pHisto can be overwritten or setup function
2276
    // has not been called, need to relink the buffer pHisto points to.
2277
    buildHistogramInfo(pInfo);
51,474,715✔
2278
    qDebug("%s before add %d elements into histogram, total:%" PRId64 ", numOfEntry:%d, pHisto:%p, elems: %p",
51,474,715✔
2279
           __FUNCTION__, numOfElems, pInfo->pHisto->numOfElems, pInfo->pHisto->numOfEntries, pInfo->pHisto,
2280
           pInfo->pHisto->elems);
2281
    for (int32_t i = start; i < pInput->numOfRows + start; ++i) {
2,147,483,647✔
2282
      if (colDataIsNull_f(pCol, i)) {
2,147,483,647✔
2283
        continue;
2,147,483,647✔
2284
      }
2285
      numOfElems += 1;
1,878,395,405✔
2286
      char* data = colDataGetData(pCol, i);
1,878,395,405✔
2287

2288
      double v = 0;
1,879,777,690✔
2289
      GET_TYPED_DATA(v, double, type, data, typeGetTypeModFromColInfo(&pCol->info));
1,879,777,690✔
2290
      int32_t code = tHistogramAdd(&pInfo->pHisto, v);
1,879,774,186✔
2291
      if (code != TSDB_CODE_SUCCESS) {
1,871,680,426✔
UNCOV
2292
        return code;
×
2293
      }
2294
    }
2295

2296
    qDebug("%s after add %d elements into histogram, total:%" PRId64 ", numOfEntry:%d, pHisto:%p, elems: %p",
51,474,715✔
2297
           __FUNCTION__, numOfElems, pInfo->pHisto->numOfElems, pInfo->pHisto->numOfEntries, pInfo->pHisto,
2298
           pInfo->pHisto->elems);
2299
  }
2300

2301
  SET_VAL(pResInfo, numOfElems, 1);
52,921,565✔
2302
  return TSDB_CODE_SUCCESS;
52,921,565✔
2303
}
2304

2305
static int32_t apercentileTransferInfo(SAPercentileInfo* pInput, SAPercentileInfo* pOutput, bool* hasRes) {
493,143✔
2306
  pOutput->percent = pInput->percent;
493,143✔
2307
  pOutput->algo = pInput->algo;
493,143✔
2308
  if (pOutput->algo == APERCT_ALGO_TDIGEST) {
493,143✔
2309
    buildTDigestInfo(pInput);
13,826✔
2310
    tdigestAutoFill(pInput->pTDigest, COMPRESSION);
13,826✔
2311

2312
    if (pInput->pTDigest->num_centroids == 0 && pInput->pTDigest->num_buffered_pts == 0) {
13,826✔
2313
      return TSDB_CODE_SUCCESS;
446✔
2314
    }
2315

2316
    if (hasRes) {
13,380✔
2317
      *hasRes = true;
13,380✔
2318
    }
2319

2320
    buildTDigestInfo(pOutput);
13,380✔
2321
    TDigest* pTDigest = pOutput->pTDigest;
13,380✔
2322
    tdigestAutoFill(pTDigest, COMPRESSION);
13,380✔
2323

2324
    if (pTDigest->num_centroids <= 0 && pTDigest->num_buffered_pts == 0) {
13,380✔
2325
      (void)memcpy(pTDigest, pInput->pTDigest, (size_t)TDIGEST_SIZE(COMPRESSION));
13,380✔
2326
      tdigestAutoFill(pTDigest, COMPRESSION);
13,380✔
2327
    } else {
2328
      int32_t code = tdigestMerge(pTDigest, pInput->pTDigest);
×
UNCOV
2329
      if (TSDB_CODE_SUCCESS != code) {
×
UNCOV
2330
        return code;
×
2331
      }
2332
    }
2333
  } else {
2334
    buildHistogramInfo(pInput);
479,317✔
2335
    if (pInput->pHisto->numOfElems <= 0) {
479,317✔
2336
      return TSDB_CODE_SUCCESS;
265,749✔
2337
    }
2338

2339
    if (hasRes) {
213,568✔
2340
      *hasRes = true;
213,568✔
2341
    }
2342

2343
    buildHistogramInfo(pOutput);
213,568✔
2344
    SHistogramInfo* pHisto = pOutput->pHisto;
213,568✔
2345

2346
    if (pHisto->numOfElems <= 0) {
213,568✔
2347
      (void)memcpy(pHisto, pInput->pHisto, sizeof(SHistogramInfo) + sizeof(SHistBin) * (MAX_HISTOGRAM_BIN + 1));
198,812✔
2348
      pHisto->elems = (SHistBin*)((char*)pHisto + sizeof(SHistogramInfo));
198,812✔
2349

2350
      qDebug("%s merge histo, total:%" PRId64 ", entry:%d, %p", __FUNCTION__, pHisto->numOfElems, pHisto->numOfEntries,
198,812✔
2351
             pHisto);
2352
    } else {
2353
      pHisto->elems = (SHistBin*)((char*)pHisto + sizeof(SHistogramInfo));
14,756✔
2354
      qDebug("%s input histogram, elem:%" PRId64 ", entry:%d, %p", __FUNCTION__, pHisto->numOfElems,
14,756✔
2355
             pHisto->numOfEntries, pInput->pHisto);
2356

2357
      SHistogramInfo* pRes = NULL;
14,756✔
2358
      int32_t         code = tHistogramMerge(pHisto, pInput->pHisto, MAX_HISTOGRAM_BIN, &pRes);
14,756✔
2359
      if (TSDB_CODE_SUCCESS != code) {
14,756✔
UNCOV
2360
        tHistogramDestroy(&pRes);
×
UNCOV
2361
        return code;
×
2362
      }
2363
      (void)memcpy(pHisto, pRes, sizeof(SHistogramInfo) + sizeof(SHistBin) * MAX_HISTOGRAM_BIN);
14,756✔
2364
      pHisto->elems = (SHistBin*)((char*)pHisto + sizeof(SHistogramInfo));
14,756✔
2365

2366
      qDebug("%s merge histo, total:%" PRId64 ", entry:%d, %p", __FUNCTION__, pHisto->numOfElems, pHisto->numOfEntries,
14,756✔
2367
             pHisto);
2368
      tHistogramDestroy(&pRes);
14,756✔
2369
    }
2370
  }
2371
  return TSDB_CODE_SUCCESS;
226,948✔
2372
}
2373

2374
int32_t apercentileFunctionMerge(SqlFunctionCtx* pCtx) {
491,101✔
2375
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
491,101✔
2376

2377
  SInputColumnInfoData* pInput = &pCtx->input;
491,101✔
2378

2379
  SColumnInfoData* pCol = pInput->pData[0];
491,101✔
2380
  if (pCol->info.type != TSDB_DATA_TYPE_BINARY) {
491,101✔
UNCOV
2381
    return TSDB_CODE_FUNC_FUNTION_PARA_TYPE;
×
2382
  }
2383

2384
  SAPercentileInfo* pInfo = GET_ROWCELL_INTERBUF(pResInfo);
491,101✔
2385

2386
  qDebug("%s total %" PRId64 " rows will merge, %p", __FUNCTION__, pInput->numOfRows, pInfo->pHisto);
491,101✔
2387

2388
  bool    hasRes = false;
491,101✔
2389
  int32_t start = pInput->startRowIndex;
491,101✔
2390
  for (int32_t i = start; i < start + pInput->numOfRows; ++i) {
984,244✔
2391
    char* data = colDataGetData(pCol, i);
493,143✔
2392

2393
    SAPercentileInfo* pInputInfo = (SAPercentileInfo*)varDataVal(data);
493,143✔
2394
    int32_t           code = apercentileTransferInfo(pInputInfo, pInfo, &hasRes);
493,143✔
2395
    if (TSDB_CODE_SUCCESS != code) {
493,143✔
UNCOV
2396
      return code;
×
2397
    }
2398
  }
2399

2400
  if (pInfo->algo != APERCT_ALGO_TDIGEST) {
491,101✔
2401
    buildHistogramInfo(pInfo);
477,275✔
2402
    qDebug("%s after merge, total:%" PRId64 ", numOfEntry:%d, %p", __FUNCTION__, pInfo->pHisto->numOfElems,
477,275✔
2403
           pInfo->pHisto->numOfEntries, pInfo->pHisto);
2404
  }
2405

2406
  SET_VAL(pResInfo, hasRes ? 1 : 0, 1);
491,101✔
2407
  return TSDB_CODE_SUCCESS;
491,101✔
2408
}
2409

2410
int32_t apercentileFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
41,048,086✔
2411
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
41,048,086✔
2412
  SAPercentileInfo*    pInfo = (SAPercentileInfo*)GET_ROWCELL_INTERBUF(pResInfo);
41,048,600✔
2413

2414
  if (pInfo->algo == APERCT_ALGO_TDIGEST) {
41,048,600✔
2415
    buildTDigestInfo(pInfo);
1,433,034✔
2416
    tdigestAutoFill(pInfo->pTDigest, COMPRESSION);
1,433,034✔
2417
    if (pInfo->pTDigest->size > 0) {
1,432,520✔
2418
      pInfo->result = tdigestQuantile(pInfo->pTDigest, pInfo->percent / 100);
1,432,520✔
2419
    } else {  // no need to free
2420
      // setNull(pCtx->pOutput, pCtx->outputType, pCtx->outputBytes);
UNCOV
2421
      return TSDB_CODE_SUCCESS;
×
2422
    }
2423
  } else {
2424
    buildHistogramInfo(pInfo);
39,615,566✔
2425
    if (pInfo->pHisto->numOfElems > 0) {
39,615,566✔
2426
      qDebug("%s get the final res, elements:%" PRId64 ", numOfEntry:%d, pHisto:%p, elems:%p", __FUNCTION__,
9,002,917✔
2427
             pInfo->pHisto->numOfElems, pInfo->pHisto->numOfEntries, pInfo->pHisto, pInfo->pHisto->elems);
2428

2429
      double  ratio[] = {pInfo->percent};
9,002,917✔
2430
      double* res = NULL;
9,002,917✔
2431
      int32_t code = tHistogramUniform(pInfo->pHisto, ratio, 1, &res);
9,002,917✔
2432
      if (TSDB_CODE_SUCCESS != code) {
9,002,917✔
UNCOV
2433
        taosMemoryFree(res);
×
UNCOV
2434
        return code;
×
2435
      }
2436
      pInfo->result = *res;
9,002,917✔
2437
      // memcpy(pCtx->pOutput, res, sizeof(double));
2438
      taosMemoryFree(res);
9,002,917✔
2439
    } else {  // no need to free
2440
      // setNull(pCtx->pOutput, pCtx->outputType, pCtx->outputBytes);
2441
      // return TSDB_CODE_SUCCESS;
2442
      qDebug("%s get the final res, elements:%" PRId64 ", numOfEntry:%d. result is null", __FUNCTION__,
30,612,649✔
2443
             pInfo->pHisto->numOfElems, pInfo->pHisto->numOfEntries);
2444
    }
2445
  }
2446

2447
  return functionFinalize(pCtx, pBlock);
41,048,086✔
2448
}
2449

2450
int32_t apercentilePartialFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
493,143✔
2451
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
493,143✔
2452
  SAPercentileInfo*    pInfo = (SAPercentileInfo*)GET_ROWCELL_INTERBUF(pResInfo);
493,143✔
2453

2454
  int32_t resultBytes = getApercentileMaxSize();
493,143✔
2455
  char*   res = taosMemoryCalloc(resultBytes + VARSTR_HEADER_SIZE, sizeof(char));
493,143✔
2456
  if (NULL == res) {
493,143✔
UNCOV
2457
    return terrno;
×
2458
  }
2459

2460
  if (pInfo->algo == APERCT_ALGO_TDIGEST) {
493,143✔
2461
    (void)memcpy(varDataVal(res), pInfo, resultBytes);
13,826✔
2462
    varDataSetLen(res, resultBytes);
13,826✔
2463
  } else {
2464
    (void)memcpy(varDataVal(res), pInfo, resultBytes);
479,317✔
2465
    varDataSetLen(res, resultBytes);
479,317✔
2466
  }
2467

2468
  int32_t          slotId = pCtx->pExpr->base.resSchema.slotId;
493,143✔
2469
  SColumnInfoData* pCol = taosArrayGet(pBlock->pDataBlock, slotId);
493,143✔
2470
  if (NULL == pCol) {
493,143✔
UNCOV
2471
    taosMemoryFree(res);
×
UNCOV
2472
    return TSDB_CODE_OUT_OF_RANGE;
×
2473
  }
2474

2475
  int32_t code = colDataSetVal(pCol, pBlock->info.rows, res, false);
493,143✔
2476

2477
  taosMemoryFree(res);
493,143✔
2478
  return code;
493,143✔
2479
}
2480

2481
int32_t apercentileCombine(SqlFunctionCtx* pDestCtx, SqlFunctionCtx* pSourceCtx) {
×
UNCOV
2482
  SResultRowEntryInfo* pDResInfo = GET_RES_INFO(pDestCtx);
×
2483
  SAPercentileInfo*    pDBuf = GET_ROWCELL_INTERBUF(pDResInfo);
×
2484

UNCOV
2485
  SResultRowEntryInfo* pSResInfo = GET_RES_INFO(pSourceCtx);
×
2486
  SAPercentileInfo*    pSBuf = GET_ROWCELL_INTERBUF(pSResInfo);
×
2487

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

2490
  int32_t code = apercentileTransferInfo(pSBuf, pDBuf, NULL);
×
UNCOV
2491
  if (TSDB_CODE_SUCCESS != code) {
×
2492
    return code;
×
2493
  }
2494
  pDResInfo->numOfRes = TMAX(pDResInfo->numOfRes, pSResInfo->numOfRes);
×
UNCOV
2495
  pDResInfo->isNullRes &= pSResInfo->isNullRes;
×
UNCOV
2496
  return TSDB_CODE_SUCCESS;
×
2497
}
2498

2499
// TODO: change this function when block data info pks changed
2500
static int32_t comparePkDataWithSValue(int8_t pkType, char* pkData, SValue* pVal, int32_t order) {
362,043✔
2501
  char numVal[8] = {0};
362,043✔
2502
  switch (pkType) {
362,043✔
2503
    case TSDB_DATA_TYPE_INT:
48,411✔
2504
      *(int32_t*)numVal = (int32_t)VALUE_GET_TRIVIAL_DATUM(pVal);
48,411✔
2505
      break;
48,411✔
2506
    case TSDB_DATA_TYPE_UINT:
21,210✔
2507
      *(uint32_t*)numVal = (uint32_t)VALUE_GET_TRIVIAL_DATUM(pVal);
21,210✔
2508
      break;
21,210✔
2509
    case TSDB_DATA_TYPE_BIGINT:
95,858✔
2510
      *(int64_t*)numVal = (int64_t)VALUE_GET_TRIVIAL_DATUM(pVal);
95,858✔
2511
      break;
95,858✔
2512
    case TSDB_DATA_TYPE_UBIGINT:
77,196✔
2513
      *(uint64_t*)numVal = (uint64_t)VALUE_GET_TRIVIAL_DATUM(pVal);
77,196✔
2514
      break;
77,196✔
2515
    default:
119,368✔
2516
      break;
119,368✔
2517
  }
2518
  char*         blockData = (IS_NUMERIC_TYPE(pkType)) ? (char*)numVal : (char*)pVal->pData;
362,043✔
2519
  __compar_fn_t fn = getKeyComparFunc(pkType, order);
362,043✔
2520
  return fn(pkData, blockData);
362,043✔
2521
}
2522

2523
EFuncDataRequired firstDynDataReq(void* pRes, SDataBlockInfo* pBlockInfo) {
2,147,483,647✔
2524
  SResultRowEntryInfo* pEntry = (SResultRowEntryInfo*)pRes;
2,147,483,647✔
2525

2526
  // not initialized yet, data is required
2527
  if (pEntry == NULL) {
2,147,483,647✔
UNCOV
2528
    return FUNC_DATA_REQUIRED_DATA_LOAD;
×
2529
  }
2530

2531
  SFirstLastRes* pResult = GET_ROWCELL_INTERBUF(pEntry);
2,147,483,647✔
2532
  if (pResult->hasResult) {
2,147,483,647✔
2533
    if (pResult->pkBytes > 0) {
2,147,483,647✔
2534
      pResult->pkData = pResult->buf + pResult->bytes;
758,128✔
2535
    } else {
2536
      pResult->pkData = NULL;
2,147,483,647✔
2537
    }
2538
    if (pResult->ts < pBlockInfo->window.skey) {
2,147,483,647✔
2539
      return FUNC_DATA_REQUIRED_NOT_LOAD;
9,750,712✔
2540
    } else if (pResult->ts == pBlockInfo->window.skey) {
2,147,483,647✔
2541
      if (NULL == pResult->pkData) {
2,147,483,647✔
2542
        return FUNC_DATA_REQUIRED_NOT_LOAD;
2,147,483,647✔
2543
      }
2544
      if (comparePkDataWithSValue(pResult->pkType, pResult->pkData, pBlockInfo->pks + 0, TSDB_ORDER_ASC) < 0) {
155,904✔
2545
        return FUNC_DATA_REQUIRED_NOT_LOAD;
10,010✔
2546
      }
2547
    }
2548
    return FUNC_DATA_REQUIRED_DATA_LOAD;
550,302✔
2549
  } else {
2550
    return FUNC_DATA_REQUIRED_DATA_LOAD;
7,907,187✔
2551
  }
2552
}
2553

2554
EFuncDataRequired lastDynDataReq(void* pRes, SDataBlockInfo* pBlockInfo) {
52,349,378✔
2555
  SResultRowEntryInfo* pEntry = (SResultRowEntryInfo*)pRes;
52,349,378✔
2556

2557
  // not initialized yet, data is required
2558
  if (pEntry == NULL) {
52,349,378✔
UNCOV
2559
    return FUNC_DATA_REQUIRED_DATA_LOAD;
×
2560
  }
2561

2562
  SFirstLastRes* pResult = GET_ROWCELL_INTERBUF(pEntry);
52,349,378✔
2563
  if (pResult->hasResult) {
52,358,803✔
2564
    if (pResult->pkBytes > 0) {
44,603,061✔
2565
      pResult->pkData = pResult->buf + pResult->bytes;
1,027,225✔
2566
    } else {
2567
      pResult->pkData = NULL;
43,575,200✔
2568
    }
2569
    if (pResult->ts > pBlockInfo->window.ekey) {
44,602,403✔
2570
      return FUNC_DATA_REQUIRED_NOT_LOAD;
26,415,044✔
2571
    } else if (pResult->ts == pBlockInfo->window.ekey && pResult->pkData) {
18,187,359✔
2572
      if (comparePkDataWithSValue(pResult->pkType, pResult->pkData, pBlockInfo->pks + 1, TSDB_ORDER_DESC) < 0) {
206,139✔
2573
        return FUNC_DATA_REQUIRED_NOT_LOAD;
64,322✔
2574
      }
2575
    }
2576
    return FUNC_DATA_REQUIRED_DATA_LOAD;
18,120,946✔
2577
  } else {
2578
    return FUNC_DATA_REQUIRED_DATA_LOAD;
7,757,211✔
2579
  }
2580
}
2581

2582
// TODO modify it to include primary key bytes
2583
int32_t getFirstLastInfoSize(int32_t resBytes, int32_t pkBytes) { return sizeof(SFirstLastRes) + resBytes + pkBytes; }
1,731,248,771✔
2584

2585
bool getFirstLastFuncEnv(SFunctionNode* pFunc, SFuncExecEnv* pEnv) {
69,304,616✔
2586
  SColumnNode* pNode = (SColumnNode*)nodesListGetNode(pFunc->pParameterList, 0);
69,304,616✔
2587
  // TODO: change SFunctionNode to add pk info
2588
  int32_t pkBytes = (pFunc->hasPk) ? pFunc->pkBytes : 0;
69,309,983✔
2589
  pEnv->calcMemSize = getFirstLastInfoSize(pNode->node.resType.bytes, pkBytes);
69,302,307✔
2590
  return true;
69,296,216✔
2591
}
2592

2593
bool getSelectivityFuncEnv(SFunctionNode* pFunc, SFuncExecEnv* pEnv) {
15,213,845✔
2594
  SColumnNode* pNode = (SColumnNode*)nodesListGetNode(pFunc->pParameterList, 0);
15,213,845✔
2595
  pEnv->calcMemSize = pNode->node.resType.bytes;
15,214,891✔
2596
  return true;
15,213,636✔
2597
}
2598

2599

2600
bool getHasNullFuncEnv(SFunctionNode* pFunc, SFuncExecEnv* pEnv) {
19,861,668✔
2601
  pEnv->calcMemSize = pFunc->node.resType.bytes;
19,861,668✔
2602
  return true;
19,861,668✔
2603
}
2604

2605
bool getGroupKeyFuncEnv(SFunctionNode* pFunc, SFuncExecEnv* pEnv) {
48,446,939✔
2606
  SColumnNode* pNode = (SColumnNode*)nodesListGetNode(pFunc->pParameterList, 0);
48,446,939✔
2607
  pEnv->calcMemSize = sizeof(SGroupKeyInfo) + pNode->node.resType.bytes;
48,456,438✔
2608
  return true;
48,445,169✔
2609
}
2610

2611
static FORCE_INLINE TSKEY getRowPTs(SColumnInfoData* pTsColInfo, int32_t rowIndex) {
2612
  if (pTsColInfo == NULL || pTsColInfo->pData == NULL) {
2,147,483,647✔
2613
    return 0;
×
2614
  }
2615

2616
  return *(TSKEY*)colDataGetData(pTsColInfo, rowIndex);
2,147,483,647✔
2617
}
2618

2619
int32_t firstLastFunctionSetup(SqlFunctionCtx* pCtx, SResultRowEntryInfo* pResInfo) {
2,147,483,647✔
2620
  if (pResInfo->initialized) {
2,147,483,647✔
UNCOV
2621
    return TSDB_CODE_SUCCESS;
×
2622
  }
2623
  if (TSDB_CODE_SUCCESS != functionSetup(pCtx, pResInfo)) {
2,147,483,647✔
UNCOV
2624
    return TSDB_CODE_FUNC_SETUP_ERROR;
×
2625
  }
2626

2627
  SFirstLastRes* pRes = GET_ROWCELL_INTERBUF(pResInfo);
2,147,483,647✔
2628
  pRes->nullTupleSaved = false;
2,147,483,647✔
2629
  pRes->nullTuplePos.pageId = -1;
2,147,483,647✔
2630
  return TSDB_CODE_SUCCESS;
2,147,483,647✔
2631
}
2632

2633
static int32_t prepareBuf(SqlFunctionCtx* pCtx) {
139,978,910✔
2634
  if (pCtx->subsidiaries.rowLen == 0) {
139,978,910✔
2635
    int32_t rowLen = 0;
5,189,945✔
2636
    for (int32_t j = 0; j < pCtx->subsidiaries.num; ++j) {
12,233,513✔
2637
      SqlFunctionCtx* pc = pCtx->subsidiaries.pCtx[j];
7,046,717✔
2638
      rowLen += pc->pExpr->base.resSchema.bytes;
7,045,398✔
2639
    }
2640

2641
    pCtx->subsidiaries.rowLen = rowLen + pCtx->subsidiaries.num * sizeof(bool);
5,188,156✔
2642
    pCtx->subsidiaries.buf = taosMemoryMalloc(pCtx->subsidiaries.rowLen);
5,188,497✔
2643
    if (NULL == pCtx->subsidiaries.buf) {
5,192,197✔
UNCOV
2644
      return terrno;
×
2645
    }
2646
  }
2647
  return TSDB_CODE_SUCCESS;
139,979,310✔
2648
}
2649

2650
static int32_t firstlastSaveTupleData(const SSDataBlock* pSrcBlock, int32_t rowIndex, SqlFunctionCtx* pCtx,
2,147,483,647✔
2651
                                      SFirstLastRes* pInfo, bool noElements) {
2652
  int32_t code = TSDB_CODE_SUCCESS;
2,147,483,647✔
2653

2654
  if (pCtx->subsidiaries.num <= 0) {
2,147,483,647✔
2655
    return TSDB_CODE_SUCCESS;
2,147,483,647✔
2656
  }
2657

2658
  if (!pInfo->hasResult) {
99,802,818✔
2659
    code = saveTupleData(pCtx, rowIndex, pSrcBlock, &pInfo->pos);
87,353,303✔
2660
  } else if (!noElements) {
12,451,321✔
2661
    code = updateTupleData(pCtx, rowIndex, pSrcBlock, &pInfo->pos);
12,436,519✔
2662
  } else {
2663
  }  // dothing
2664

2665
  return code;
99,804,491✔
2666
}
2667

2668
static int32_t doSaveCurrentVal(SqlFunctionCtx* pCtx, int32_t rowIndex, int64_t currentTs, char* pkData, int32_t type,
2,147,483,647✔
2669
                                char* pData) {
2670
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
2,147,483,647✔
2671
  SFirstLastRes*       pInfo = GET_ROWCELL_INTERBUF(pResInfo);
2,147,483,647✔
2672

2673
  if (IS_VAR_DATA_TYPE(type)) {
2,147,483,647✔
2674
    pInfo->bytes = calcStrBytesByType(type, pData);
2,147,483,647✔
2675
    // if (type == TSDB_DATA_TYPE_JSON) {
2676
    //   pInfo->bytes = getJsonValueLen(pData);
2677
    // } else {
2678
    //   pInfo->bytes = varDataTLen(pData);
2679
    // }
2680
  }
2681

2682
  (void)memcpy(pInfo->buf, pData, pInfo->bytes);
2,147,483,647✔
2683
  if (pkData != NULL) {
2,147,483,647✔
2684
    if (IS_VAR_DATA_TYPE(pInfo->pkType)) {
168,532,215✔
2685
      pInfo->pkBytes = calcStrBytesByType(pInfo->pkType, pkData);
56,018,503✔
2686
      // if (pInfo->pkType == TSDB_DATA_TYPE_JSON) {
2687
      //   pInfo->pkBytes = getJsonValueLen(pkData);
2688
      // } else {
2689
      //   pInfo->pkBytes = varDataTLen(pkData);
2690
      // }
2691
    }
2692
    (void)memcpy(pInfo->buf + pInfo->bytes, pkData, pInfo->pkBytes);
168,548,875✔
2693
    pInfo->pkData = pInfo->buf + pInfo->bytes;
168,551,122✔
2694
  }
2695

2696
  pInfo->ts = currentTs;
2,147,483,647✔
2697
  int32_t code = firstlastSaveTupleData(pCtx->pSrcBlock, rowIndex, pCtx, pInfo, false);
2,147,483,647✔
2698
  if (code != TSDB_CODE_SUCCESS) {
2,147,483,647✔
UNCOV
2699
    return code;
×
2700
  }
2701

2702
  pInfo->hasResult = true;
2,147,483,647✔
2703
  return TSDB_CODE_SUCCESS;
2,147,483,647✔
2704
}
2705

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

2711
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
2,147,483,647✔
2712
  SFirstLastRes*       pInfo = GET_ROWCELL_INTERBUF(pResInfo);
2,147,483,647✔
2713

2714
  SInputColumnInfoData* pInput = &pCtx->input;
2,147,483,647✔
2715
  SColumnInfoData*      pInputCol = pInput->pData[0];
2,147,483,647✔
2716

2717
  pInfo->bytes = pInputCol->info.bytes;
2,147,483,647✔
2718

2719
  if (IS_NULL_TYPE(pInputCol->info.type)) {
2,147,483,647✔
2720
    return TSDB_CODE_SUCCESS;
626,177✔
2721
  }
2722

2723
  SColumnInfoData* pkCol = pInput->pPrimaryKey;
2,147,483,647✔
2724
  pInfo->pkType = -1;
2,147,483,647✔
2725
  __compar_fn_t pkCompareFn = NULL;
2,147,483,647✔
2726
  if (pCtx->hasPrimaryKey) {
2,147,483,647✔
2727
    pInfo->pkType = pkCol->info.type;
45,649,439✔
2728
    pInfo->pkBytes = pkCol->info.bytes;
45,652,974✔
2729
    pkCompareFn = getKeyComparFunc(pInfo->pkType, TSDB_ORDER_ASC);
45,642,852✔
2730
  }
2731

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

2744
  SColumnDataAgg* pColAgg = (pInput->colDataSMAIsSet) ? pInput->pColumnDataAgg[0] : NULL;
2,147,483,647✔
2745

2746
  TSKEY startKey = getRowPTs(pInput->pPTS, 0);
2,147,483,647✔
2747
  TSKEY endKey = getRowPTs(pInput->pPTS, pInput->totalRows - 1);
2,147,483,647✔
2748

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

2751
  //  please ref. to the comment in lastRowFunction for the reason why disabling the opt version of last/first
2752
  //  function. we will use this opt implementation in an new version that is only available in scan subplan
2753
#if 0
2754
  if (blockDataOrder == TSDB_ORDER_ASC) {
2755
    // filter according to current result firstly
2756
    if (pResInfo->numOfRes > 0) {
2757
      if (pInfo->ts < startKey) {
2758
        return TSDB_CODE_SUCCESS;
2759
      }
2760
    }
2761

2762
    for (int32_t i = pInput->startRowIndex; i < pInput->startRowIndex + pInput->numOfRows; ++i) {
2763
      if (pInputCol->hasNull && colDataIsNull(pInputCol, pInput->totalRows, i, pColAgg)) {
2764
        continue;
2765
      }
2766

2767
      numOfElems++;
2768

2769
      char* data = colDataGetData(pInputCol, i);
2770
      TSKEY cts = getRowPTs(pInput->pPTS, i);
2771
      if (pResInfo->numOfRes == 0 || pInfo->ts > cts) {
2772
        doSaveCurrentVal(pCtx, i, cts, pInputCol->info.type, data);
2773
        break;
2774
      }
2775
    }
2776
  } else {
2777
    // in case of descending order time stamp serial, which usually happens as the results of the nest query,
2778
    // all data needs to be check.
2779
    if (pResInfo->numOfRes > 0) {
2780
      if (pInfo->ts < endKey) {
2781
        return TSDB_CODE_SUCCESS;
2782
      }
2783
    }
2784

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

2790
      numOfElems++;
2791

2792
      char* data = colDataGetData(pInputCol, i);
2793
      TSKEY cts = getRowPTs(pInput->pPTS, i);
2794

2795
      if (pResInfo->numOfRes == 0 || pInfo->ts > cts) {
2796
        doSaveCurrentVal(pCtx, i, cts, pInputCol->info.type, data);
2797
        break;
2798
      }
2799
    }
2800
  }
2801
#else
2802
  int64_t* pts = (int64_t*)pInput->pPTS->pData;
2,147,483,647✔
2803

2804
  int     from = -1;
2,147,483,647✔
2805
  int32_t i = -1;
2,147,483,647✔
2806
  while (funcInputGetNextRowIndex(pInput, from, true, &i, &from)) {
2,147,483,647✔
2807
    if (pInputCol->hasNull && colDataIsNull(pInputCol, pInput->totalRows, i, pColAgg)) {
2,147,483,647✔
2808
      continue;
2,147,483,647✔
2809
    }
2810

2811
    numOfElems++;
2,147,483,647✔
2812
    char* data = colDataGetData(pInputCol, i);
2,147,483,647✔
2813
    char* pkData = NULL;
2,147,483,647✔
2814
    if (pCtx->hasPrimaryKey) {
2,147,483,647✔
2815
      pkData = colDataGetData(pkCol, i);
162,711,944✔
2816
    }
2817
    TSKEY cts = pts[i];
2,147,483,647✔
2818
    if (pResInfo->numOfRes == 0 || pInfo->ts > cts ||
2,147,483,647✔
2819
        (pInfo->ts == cts && pkCompareFn && pkCompareFn(pkData, pInfo->pkData) < 0)) {
2,147,483,647✔
2820
      int32_t code = doSaveCurrentVal(pCtx, i, cts, pkData, pInputCol->info.type, data);
2,147,483,647✔
2821
      if (code != TSDB_CODE_SUCCESS) {
2,147,483,647✔
UNCOV
2822
        return code;
×
2823
      }
2824
      pResInfo->numOfRes = 1;
2,147,483,647✔
2825
    }
2826
  }
2827
#endif
2828

2829
  if (numOfElems == 0) {
2,147,483,647✔
2830
    // save selectivity value for column consisted of all null values
2831
    int32_t code = firstlastSaveTupleData(pCtx->pSrcBlock, pInput->startRowIndex, pCtx, pInfo, true);
2,147,483,647✔
2832
    if (code != TSDB_CODE_SUCCESS) {
2,147,483,647✔
UNCOV
2833
      return code;
×
2834
    }
2835
    pInfo->nullTupleSaved = true;
2,147,483,647✔
2836
  }
2837
  SET_VAL(pResInfo, numOfElems, 1);
2,147,483,647✔
2838
  return TSDB_CODE_SUCCESS;
2,147,483,647✔
2839
}
2840

2841
int32_t lastFunction(SqlFunctionCtx* pCtx) {
2,147,483,647✔
2842
  int32_t numOfElems = 0;
2,147,483,647✔
2843

2844
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
2,147,483,647✔
2845
  SFirstLastRes*       pInfo = GET_ROWCELL_INTERBUF(pResInfo);
2,147,483,647✔
2846

2847
  SInputColumnInfoData* pInput = &pCtx->input;
2,147,483,647✔
2848
  SColumnInfoData*      pInputCol = pInput->pData[0];
2,147,483,647✔
2849

2850
  int32_t type = pInputCol->info.type;
2,147,483,647✔
2851
  int32_t bytes = pInputCol->info.bytes;
2,147,483,647✔
2852

2853
  if (IS_NULL_TYPE(type)) {
2,147,483,647✔
2854
    return TSDB_CODE_SUCCESS;
603,908✔
2855
  }
2856
  pInfo->bytes = bytes;
2,147,483,647✔
2857

2858
  SColumnInfoData* pkCol = pInput->pPrimaryKey;
2,147,483,647✔
2859
  pInfo->pkType = -1;
2,147,483,647✔
2860
  __compar_fn_t pkCompareFn = NULL;
2,147,483,647✔
2861
  if (pCtx->hasPrimaryKey) {
2,147,483,647✔
2862
    pInfo->pkType = pkCol->info.type;
45,771,858✔
2863
    pInfo->pkBytes = pkCol->info.bytes;
45,785,452✔
2864
    pkCompareFn = getKeyComparFunc(pInfo->pkType, TSDB_ORDER_DESC);
45,786,733✔
2865
  }
2866

2867
  // All null data column, return directly.
2868
  if (pInput->colDataSMAIsSet && (pInput->pColumnDataAgg[0]->numOfNull == pInput->totalRows) &&
2,147,483,647✔
UNCOV
2869
      pInputCol->hasNull == true) {
×
2870
    // save selectivity value for column consisted of all null values
UNCOV
2871
    int32_t code = firstlastSaveTupleData(pCtx->pSrcBlock, pInput->startRowIndex, pCtx, pInfo, true);
×
UNCOV
2872
    if (code != TSDB_CODE_SUCCESS) {
×
UNCOV
2873
      return code;
×
2874
    }
UNCOV
2875
    pInfo->nullTupleSaved = true;
×
UNCOV
2876
    return TSDB_CODE_SUCCESS;
×
2877
  }
2878

2879
  SColumnDataAgg* pColAgg = (pInput->colDataSMAIsSet) ? pInput->pColumnDataAgg[0] : NULL;
2,147,483,647✔
2880

2881
  TSKEY startKey = getRowPTs(pInput->pPTS, 0);
2,147,483,647✔
2882
  TSKEY endKey = getRowPTs(pInput->pPTS, pInput->totalRows - 1);
2,147,483,647✔
2883

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

2886
  //  please ref. to the comment in lastRowFunction for the reason why disabling the opt version of last/first function.
2887
#if 0
2888
  if (blockDataOrder == TSDB_ORDER_ASC) {
2889
    for (int32_t i = pInput->numOfRows + pInput->startRowIndex - 1; i >= pInput->startRowIndex; --i) {
2890
      if (pInputCol->hasNull && colDataIsNull(pInputCol, pInput->totalRows, i, pColAgg)) {
2891
        continue;
2892
      }
2893

2894
      numOfElems++;
2895

2896
      char* data = colDataGetData(pInputCol, i);
2897
      TSKEY cts = getRowPTs(pInput->pPTS, i);
2898
      if (pResInfo->numOfRes == 0 || pInfo->ts < cts) {
2899
        doSaveCurrentVal(pCtx, i, cts, type, data);
2900
      }
2901

2902
      break;
2903
    }
2904
  } else {  // descending order
2905
    for (int32_t i = pInput->startRowIndex; i < pInput->numOfRows + pInput->startRowIndex; ++i) {
2906
      if (pInputCol->hasNull && colDataIsNull(pInputCol, pInput->totalRows, i, pColAgg)) {
2907
        continue;
2908
      }
2909

2910
      numOfElems++;
2911

2912
      char* data = colDataGetData(pInputCol, i);
2913
      TSKEY cts = getRowPTs(pInput->pPTS, i);
2914
      if (pResInfo->numOfRes == 0 || pInfo->ts < cts) {
2915
        doSaveCurrentVal(pCtx, i, cts, type, data);
2916
      }
2917
      break;
2918
    }
2919
  }
2920
#else
2921
  int64_t* pts = (int64_t*)pInput->pPTS->pData;
2,147,483,647✔
2922

2923
#if 0
2924
    for (int32_t i = pInput->startRowIndex; i < pInput->numOfRows + pInput->startRowIndex; ++i) {
2925
      if (pInputCol->hasNull && colDataIsNull(pInputCol, pInput->totalRows, i, pColAgg)) {
2926
        continue;
2927
      }
2928

2929
      numOfElems++;
2930
      if (pResInfo->numOfRes == 0 || pInfo->ts < pts[i]) {
2931
        char* data = colDataGetData(pInputCol, i);
2932
        doSaveCurrentVal(pCtx, i, pts[i], type, data);
2933
        pResInfo->numOfRes = 1;
2934
      }
2935
    }
2936
#else
2937

2938
  // todo refactor
2939
  if (!pInputCol->hasNull && !pCtx->hasPrimaryKey) {
2,147,483,647✔
2940
    numOfElems = 1;
2,147,483,647✔
2941

2942
    int32_t round = pInput->numOfRows >> 2;
2,147,483,647✔
2943
    int32_t reminder = pInput->numOfRows & 0x03;
2,147,483,647✔
2944

2945
    for (int32_t i = pInput->startRowIndex, tick = 0; tick < round; i += 4, tick += 1) {
2,147,483,647✔
2946
      int64_t cts = pts[i];
2,147,483,647✔
2947
      int32_t chosen = i;
2,147,483,647✔
2948

2949
      if (cts < pts[i + 1]) {
2,147,483,647✔
2950
        cts = pts[i + 1];
131,140,513✔
2951
        chosen = i + 1;
131,140,513✔
2952
      }
2953

2954
      if (cts < pts[i + 2]) {
2,147,483,647✔
2955
        cts = pts[i + 2];
131,140,779✔
2956
        chosen = i + 2;
131,140,779✔
2957
      }
2958

2959
      if (cts < pts[i + 3]) {
2,147,483,647✔
2960
        cts = pts[i + 3];
131,139,265✔
2961
        chosen = i + 3;
131,139,265✔
2962
      }
2963

2964
      if (pResInfo->numOfRes == 0 || pInfo->ts < cts) {
2,147,483,647✔
2965
        char*   data = colDataGetData(pInputCol, chosen);
160,360,029✔
2966
        int32_t code = doSaveCurrentVal(pCtx, chosen, cts, NULL, type, data);
160,277,598✔
2967
        if (code != TSDB_CODE_SUCCESS) {
160,278,626✔
UNCOV
2968
          return code;
×
2969
        }
2970
        pResInfo->numOfRes = 1;
160,278,626✔
2971
      }
2972
    }
2973

2974
    for (int32_t i = pInput->startRowIndex + round * 4; i < pInput->startRowIndex + pInput->numOfRows; ++i) {
2,147,483,647✔
2975
      if (pResInfo->numOfRes == 0 || pInfo->ts < pts[i]) {
2,147,483,647✔
2976
        char*   data = colDataGetData(pInputCol, i);
868,397,425✔
2977
        int32_t code = doSaveCurrentVal(pCtx, i, pts[i], NULL, type, data);
863,994,829✔
2978
        if (code != TSDB_CODE_SUCCESS) {
862,563,177✔
UNCOV
2979
          return code;
×
2980
        }
2981
        pResInfo->numOfRes = 1;
862,563,177✔
2982
      }
2983
    }
2984
  } else {
2985
    int     from = -1;
2,147,483,647✔
2986
    int32_t i = -1;
2,147,483,647✔
2987
    while (funcInputGetNextRowIndex(pInput, from, false, &i, &from)) {
2,147,483,647✔
2988
      if (colDataIsNull(pInputCol, pInput->totalRows, i, pColAgg)) {
2,147,483,647✔
2989
        continue;
2,147,483,647✔
2990
      }
2991

2992
      numOfElems++;
2,147,483,647✔
2993
      char* pkData = NULL;
2,147,483,647✔
2994
      if (pCtx->hasPrimaryKey && !colDataIsNull_s(pkCol, i)) {
2,147,483,647✔
2995
        // pkCol[i] might be null when using cachemodel
2996
        // however, if using cachemodel, we don't need pk to determine the order
2997
        // because ts is enough
2998
        pkData = colDataGetData(pkCol, i);
162,892,271✔
2999
      }
3000
      if (pResInfo->numOfRes == 0 || pInfo->ts < pts[i] ||
2,147,483,647✔
3001
          (pInfo->ts == pts[i] && pkCompareFn && pkCompareFn(pkData, pInfo->pkData) < 0)) {
2,147,483,647✔
3002
        char*   data = colDataGetData(pInputCol, i);
2,147,483,647✔
3003
        int32_t code = doSaveCurrentVal(pCtx, i, pts[i], pkData, type, data);
2,147,483,647✔
3004
        if (code != TSDB_CODE_SUCCESS) {
2,147,483,647✔
UNCOV
3005
          return code;
×
3006
        }
3007
        pResInfo->numOfRes = 1;
2,147,483,647✔
3008
      }
3009
    }
3010
  }
3011
#endif
3012

3013
#endif
3014

3015
  // save selectivity value for column consisted of all null values
3016
  if (numOfElems == 0) {
2,147,483,647✔
3017
    int32_t code = firstlastSaveTupleData(pCtx->pSrcBlock, pInput->startRowIndex, pCtx, pInfo, true);
2,147,483,647✔
3018
    if (code != TSDB_CODE_SUCCESS) {
2,147,483,647✔
UNCOV
3019
      return code;
×
3020
    }
3021
    pInfo->nullTupleSaved = true;
2,147,483,647✔
3022
  }
3023

3024
  return TSDB_CODE_SUCCESS;
2,147,483,647✔
3025
}
3026

3027
static bool firstLastTransferInfoImpl(SFirstLastRes* pInput, SFirstLastRes* pOutput, bool isFirst) {
1,323,951,872✔
3028
  if (!pInput->hasResult) {
1,323,951,872✔
UNCOV
3029
    return false;
×
3030
  }
3031
  __compar_fn_t pkCompareFn = NULL;
1,323,952,085✔
3032
  if (pInput->pkData) {
1,323,952,085✔
3033
    pkCompareFn = getKeyComparFunc(pInput->pkType, (isFirst) ? TSDB_ORDER_ASC : TSDB_ORDER_DESC);
4,180,471✔
3034
  }
3035
  if (pOutput->hasResult) {
1,323,952,724✔
3036
    if (isFirst) {
724,258,953✔
3037
      if (pInput->ts > pOutput->ts ||
625,304,958✔
3038
          (pInput->ts == pOutput->ts && pkCompareFn && pkCompareFn(pInput->pkData, pOutput->pkData) > 0)) {
622,731,120✔
3039
        return false;
2,629,824✔
3040
      }
3041
    } else {
3042
      if (pInput->ts < pOutput->ts ||
98,953,995✔
3043
          (pInput->ts == pOutput->ts && pkCompareFn && pkCompareFn(pInput->pkData, pOutput->pkData) > 0)) {
93,924,334✔
3044
        return false;
5,138,021✔
3045
      }
3046
    }
3047
  }
3048

3049
  pOutput->isNull = pInput->isNull;
1,316,185,305✔
3050
  pOutput->ts = pInput->ts;
1,316,185,092✔
3051
  pOutput->bytes = pInput->bytes;
1,316,185,731✔
3052
  pOutput->pkType = pInput->pkType;
1,316,187,009✔
3053

3054
  (void)memcpy(pOutput->buf, pInput->buf, pOutput->bytes);
1,316,187,648✔
3055
  if (pInput->pkData) {
1,316,187,435✔
3056
    pOutput->pkBytes = pInput->pkBytes;
3,930,767✔
3057
    (void)memcpy(pOutput->buf + pOutput->bytes, pInput->pkData, pOutput->pkBytes);
3,930,767✔
3058
    pOutput->pkData = pOutput->buf + pOutput->bytes;
3,930,767✔
3059
  }
3060
  return true;
1,316,188,287✔
3061
}
3062

3063
static int32_t firstLastTransferInfo(SqlFunctionCtx* pCtx, SFirstLastRes* pInput, SFirstLastRes* pOutput, bool isFirst,
1,323,952,298✔
3064
                                     int32_t rowIndex) {
3065
  if (firstLastTransferInfoImpl(pInput, pOutput, isFirst)) {
1,323,952,298✔
3066
    int32_t code = firstlastSaveTupleData(pCtx->pSrcBlock, rowIndex, pCtx, pOutput, false);
1,316,187,861✔
3067
    if (TSDB_CODE_SUCCESS != code) {
1,316,187,648✔
UNCOV
3068
      return code;
×
3069
    }
3070
    pOutput->hasResult = true;
1,316,187,648✔
3071
  }
3072
  return TSDB_CODE_SUCCESS;
1,323,956,132✔
3073
}
3074

3075
static int32_t firstLastFunctionMergeImpl(SqlFunctionCtx* pCtx, bool isFirstQuery) {
632,035,593✔
3076
  SInputColumnInfoData* pInput = &pCtx->input;
632,035,593✔
3077
  SColumnInfoData*      pCol = pInput->pData[0];
632,038,362✔
3078

3079
  if (IS_NULL_TYPE(pCol->info.type)) {
632,038,788✔
UNCOV
3080
    SET_VAL(GET_RES_INFO(pCtx), 0, 1);
×
UNCOV
3081
    return TSDB_CODE_SUCCESS;
×
3082
  }
3083

3084
  if (pCol->info.type != TSDB_DATA_TYPE_BINARY) {
632,040,279✔
UNCOV
3085
    return TSDB_CODE_FUNC_FUNTION_PARA_TYPE;
×
3086
  }
3087

3088
  SFirstLastRes* pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
632,038,362✔
3089

3090
  int32_t start = pInput->startRowIndex;
632,038,788✔
3091
  int32_t numOfElems = 0;
632,039,001✔
3092

3093
  for (int32_t i = start; i < start + pInput->numOfRows; ++i) {
2,147,483,647✔
3094
    if (colDataIsNull_s(pCol, i)) {
2,147,483,647✔
3095
      continue;
229,476,059✔
3096
    }
3097
    char*          data = colDataGetData(pCol, i);
1,323,954,002✔
3098
    SFirstLastRes* pInputInfo = (SFirstLastRes*)varDataVal(data);
1,323,954,002✔
3099
    if (pCtx->hasPrimaryKey) {
1,323,954,428✔
3100
      pInputInfo->pkData = pInputInfo->buf + pInputInfo->bytes;
4,180,471✔
3101
    } else {
3102
      pInputInfo->pkData = NULL;
1,319,773,318✔
3103
    }
3104

3105
    int32_t code = firstLastTransferInfo(pCtx, pInputInfo, pInfo, isFirstQuery, i);
1,323,952,511✔
3106
    if (code != TSDB_CODE_SUCCESS) {
1,323,955,493✔
UNCOV
3107
      return code;
×
3108
    }
3109
    if (!numOfElems) {
1,323,955,493✔
3110
      numOfElems = pInputInfo->hasResult ? 1 : 0;
620,931,187✔
3111
    }
3112
  }
3113

3114
  if (numOfElems == 0) {
632,036,871✔
3115
    int32_t code = firstlastSaveTupleData(pCtx->pSrcBlock, pInput->startRowIndex, pCtx, pInfo, true);
11,108,666✔
3116
    if (code != TSDB_CODE_SUCCESS) {
11,108,666✔
UNCOV
3117
      return code;
×
3118
    }
3119
    pInfo->nullTupleSaved = true;
11,108,666✔
3120
  }
3121

3122
  SET_VAL(GET_RES_INFO(pCtx), numOfElems, 1);
632,033,463✔
3123
  return TSDB_CODE_SUCCESS;
632,036,871✔
3124
}
3125

3126
int32_t firstFunctionMerge(SqlFunctionCtx* pCtx) { return firstLastFunctionMergeImpl(pCtx, true); }
362,332,791✔
3127

3128
int32_t lastFunctionMerge(SqlFunctionCtx* pCtx) { return firstLastFunctionMergeImpl(pCtx, false); }
269,705,784✔
3129

3130
int32_t firstLastFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
2,147,483,647✔
3131
  int32_t          code = TSDB_CODE_SUCCESS;
2,147,483,647✔
3132
  int32_t          slotId = pCtx->pExpr->base.resSchema.slotId;
2,147,483,647✔
3133
  SColumnInfoData* pCol = taosArrayGet(pBlock->pDataBlock, slotId);
2,147,483,647✔
3134
  if (NULL == pCol) {
2,147,483,647✔
UNCOV
3135
    return TSDB_CODE_OUT_OF_RANGE;
×
3136
  }
3137

3138
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
2,147,483,647✔
3139
  pResInfo->isNullRes = (pResInfo->numOfRes == 0) ? 1 : 0;
2,147,483,647✔
3140

3141
  SFirstLastRes* pRes = GET_ROWCELL_INTERBUF(pResInfo);
2,147,483,647✔
3142

3143
  if (pResInfo->isNullRes) {
2,147,483,647✔
3144
    colDataSetNULL(pCol, pBlock->info.rows);
1,845,497,267✔
3145
    return setNullSelectivityValue(pCtx, pBlock, pBlock->info.rows);
1,845,497,267✔
3146
  }
3147
  code = colDataSetVal(pCol, pBlock->info.rows, pRes->buf, pRes->isNull || pResInfo->isNullRes);
2,147,483,647✔
3148
  if (TSDB_CODE_SUCCESS != code) {
2,147,483,647✔
UNCOV
3149
    return code;
×
3150
  }
3151

3152
  // handle selectivity
3153
  code = setSelectivityValue(pCtx, pBlock, &pRes->pos, pBlock->info.rows);
2,147,483,647✔
3154
  if (TSDB_CODE_SUCCESS != code) {
2,147,483,647✔
UNCOV
3155
    qError("%s failed at %d, msg:%s", __func__, __LINE__, tstrerror(code));
×
3156
  }
3157

3158
  return code;
2,147,483,647✔
3159
}
3160

3161
int32_t firstLastPartialFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
1,647,984,445✔
3162
  int32_t code = TSDB_CODE_SUCCESS;
1,647,984,445✔
3163

3164
  SResultRowEntryInfo* pEntryInfo = GET_RES_INFO(pCtx);
1,647,984,445✔
3165
  SFirstLastRes*       pRes = GET_ROWCELL_INTERBUF(pEntryInfo);
1,648,797,523✔
3166

3167
  int32_t resultBytes = getFirstLastInfoSize(pRes->bytes, pRes->pkBytes);
1,648,853,984✔
3168

3169
  // todo check for failure
3170
  char* res = taosMemoryCalloc(resultBytes + VARSTR_HEADER_SIZE, sizeof(char));
1,648,580,545✔
3171
  if (NULL == res) {
1,642,198,247✔
UNCOV
3172
    return terrno;
×
3173
  }
3174
  (void)memcpy(varDataVal(res), pRes, resultBytes);
1,642,198,247✔
3175

3176
  varDataSetLen(res, resultBytes);
1,642,181,133✔
3177

3178
  int32_t          slotId = pCtx->pExpr->base.resSchema.slotId;
1,648,237,562✔
3179
  SColumnInfoData* pCol = taosArrayGet(pBlock->pDataBlock, slotId);
1,648,207,242✔
3180
  if (NULL == pCol) {
1,648,234,281✔
UNCOV
3181
    taosMemoryFree(res);
×
UNCOV
3182
    return TSDB_CODE_OUT_OF_RANGE;
×
3183
  }
3184

3185
  if (pEntryInfo->numOfRes == 0) {
1,648,234,281✔
3186
    colDataSetNULL(pCol, pBlock->info.rows);
238,855,445✔
3187
    code = setNullSelectivityValue(pCtx, pBlock, pBlock->info.rows);
238,862,705✔
3188
  } else {
3189
    code = colDataSetVal(pCol, pBlock->info.rows, res, false);
1,409,721,594✔
3190
    if (TSDB_CODE_SUCCESS != code) {
1,409,281,609✔
UNCOV
3191
      taosMemoryFree(res);
×
3192
      return code;
×
3193
    }
3194
    code = setSelectivityValue(pCtx, pBlock, &pRes->pos, pBlock->info.rows);
1,409,281,609✔
3195
  }
3196
  taosMemoryFree(res);
1,648,009,309✔
3197
  return code;
1,647,992,662✔
3198
}
3199

3200
int32_t lastCombine(SqlFunctionCtx* pDestCtx, SqlFunctionCtx* pSourceCtx) {
×
3201
  SResultRowEntryInfo* pDResInfo = GET_RES_INFO(pDestCtx);
×
3202
  SFirstLastRes*       pDBuf = GET_ROWCELL_INTERBUF(pDResInfo);
×
3203
  int32_t              bytes = pDBuf->bytes;
×
3204

UNCOV
3205
  SResultRowEntryInfo* pSResInfo = GET_RES_INFO(pSourceCtx);
×
UNCOV
3206
  SFirstLastRes*       pSBuf = GET_ROWCELL_INTERBUF(pSResInfo);
×
3207

UNCOV
3208
  pDBuf->hasResult = firstLastTransferInfoImpl(pSBuf, pDBuf, false);
×
UNCOV
3209
  pDResInfo->numOfRes = TMAX(pDResInfo->numOfRes, pSResInfo->numOfRes);
×
UNCOV
3210
  pDResInfo->isNullRes &= pSResInfo->isNullRes;
×
UNCOV
3211
  return TSDB_CODE_SUCCESS;
×
3212
}
3213

3214
static int32_t doSaveLastrow(SqlFunctionCtx* pCtx, char* pData, int32_t rowIndex, int64_t cts, SFirstLastRes* pInfo) {
32,104,593✔
3215
  SInputColumnInfoData* pInput = &pCtx->input;
32,104,593✔
3216
  SColumnInfoData*      pInputCol = pInput->pData[0];
32,122,075✔
3217
  SColumnInfoData*      pkCol = pInput->pPrimaryKey;
32,123,993✔
3218

3219
  if (colDataIsNull_s(pInputCol, rowIndex)) {
64,246,127✔
3220
    pInfo->isNull = true;
7,940,452✔
3221
  } else {
3222
    pInfo->isNull = false;
24,175,716✔
3223

3224
    if (IS_VAR_DATA_TYPE(pInputCol->info.type)) {
24,182,498✔
3225
      pInfo->bytes = calcStrBytesByType(pInputCol->info.type, pData);
4,939,683✔
3226
      // if (pInputCol->info.type == TSDB_DATA_TYPE_JSON) {
3227
      //   pInfo->bytes = getJsonValueLen(pData);
3228
      // } else {
3229
      //   pInfo->bytes = varDataTLen(pData);
3230
      // }
3231
    }
3232

3233
    (void)memcpy(pInfo->buf, pData, pInfo->bytes);
24,193,367✔
3234
  }
3235

3236
  if (pCtx->hasPrimaryKey && !colDataIsNull_s(pkCol, rowIndex)) {
41,169,524✔
3237
    char* pkData = colDataGetData(pkCol, rowIndex);
9,067,561✔
3238
    if (IS_VAR_DATA_TYPE(pInfo->pkType)) {
9,068,709✔
3239
      pInfo->pkBytes = calcStrBytesByType(pInfo->pkType, pkData);
2,945,684✔
3240
    }
3241
    (void)memcpy(pInfo->buf + pInfo->bytes, pkData, pInfo->pkBytes);
9,068,730✔
3242
    pInfo->pkData = pInfo->buf + pInfo->bytes;
9,063,312✔
3243
  }
3244
  pInfo->ts = cts;
32,108,227✔
3245
  int32_t code = firstlastSaveTupleData(pCtx->pSrcBlock, rowIndex, pCtx, pInfo, false);
32,111,241✔
3246
  if (code != TSDB_CODE_SUCCESS) {
32,111,447✔
UNCOV
3247
    return code;
×
3248
  }
3249

3250
  pInfo->hasResult = true;
32,111,447✔
3251

3252
  return TSDB_CODE_SUCCESS;
32,125,716✔
3253
}
3254

3255
int32_t lastRowFunction(SqlFunctionCtx* pCtx) {
2,147,483,647✔
3256
  int32_t numOfElems = 0;
2,147,483,647✔
3257

3258
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
2,147,483,647✔
3259
  SFirstLastRes*       pInfo = GET_ROWCELL_INTERBUF(pResInfo);
2,147,483,647✔
3260

3261
  SInputColumnInfoData* pInput = &pCtx->input;
2,147,483,647✔
3262
  SColumnInfoData*      pInputCol = pInput->pData[0];
2,147,483,647✔
3263

3264
  int32_t type = pInputCol->info.type;
2,147,483,647✔
3265
  int32_t bytes = pInputCol->info.bytes;
2,147,483,647✔
3266
  pInfo->bytes = bytes;
2,147,483,647✔
3267

3268
  if (IS_NULL_TYPE(type)) {
2,147,483,647✔
3269
    return TSDB_CODE_SUCCESS;
22,012✔
3270
  }
3271
  SColumnInfoData* pkCol = pInput->pPrimaryKey;
2,147,483,647✔
3272
  pInfo->pkType = -1;
2,147,483,647✔
3273
  __compar_fn_t pkCompareFn = NULL;
2,147,483,647✔
3274
  if (pCtx->hasPrimaryKey) {
2,147,483,647✔
3275
    pInfo->pkType = pkCol->info.type;
45,555,090✔
3276
    pInfo->pkBytes = pkCol->info.bytes;
45,574,641✔
3277
    pkCompareFn = getKeyComparFunc(pInfo->pkType, TSDB_ORDER_DESC);
45,576,503✔
3278
  }
3279
  TSKEY startKey = getRowPTs(pInput->pPTS, 0);
2,147,483,647✔
3280
  TSKEY endKey = getRowPTs(pInput->pPTS, pInput->totalRows - 1);
2,147,483,647✔
3281

3282
  if (pCtx->order == TSDB_ORDER_ASC && !pCtx->hasPrimaryKey) {
2,147,483,647✔
3283
    for (int32_t i = pInput->numOfRows + pInput->startRowIndex - 1; i >= pInput->startRowIndex; --i) {
19,826,883✔
3284
      bool  isNull = colDataIsNull(pInputCol, pInput->numOfRows, i, NULL);
9,908,066✔
3285
      char* data = isNull ? NULL : colDataGetData(pInputCol, i);
9,908,464✔
3286
      TSKEY cts = getRowPTs(pInput->pPTS, i);
9,914,651✔
3287
      numOfElems++;
9,917,561✔
3288

3289
      if (pResInfo->numOfRes == 0 || pInfo->ts < cts) {
9,917,561✔
3290
        int32_t code = doSaveLastrow(pCtx, data, i, cts, pInfo);
2,771,485✔
3291
        if (code != TSDB_CODE_SUCCESS) return code;
2,771,087✔
3292
      }
3293

3294
      break;
9,916,367✔
3295
    }
3296
  } else if (pCtx->order == TSDB_ORDER_DESC && !pCtx->hasPrimaryKey) {
2,147,483,647✔
3297
    // the optimized version only valid if all tuples in one block are monotonious increasing or descreasing.
3298
    // this assumption is NOT always works if project operator exists in downstream.
3299
    for (int32_t i = pInput->startRowIndex; i < pInput->numOfRows + pInput->startRowIndex; ++i) {
2,147,483,647✔
3300
      bool  isNull = colDataIsNull(pInputCol, pInput->numOfRows, i, NULL);
2,147,483,647✔
3301
      char* data = isNull ? NULL : colDataGetData(pInputCol, i);
2,147,483,647✔
3302
      TSKEY cts = getRowPTs(pInput->pPTS, i);
2,147,483,647✔
3303
      numOfElems++;
2,147,483,647✔
3304

3305
      if (pResInfo->numOfRes == 0 || pInfo->ts < cts) {
2,147,483,647✔
3306
        int32_t code = doSaveLastrow(pCtx, data, i, cts, pInfo);
19,030,670✔
3307
        if (code != TSDB_CODE_SUCCESS) return code;
18,283,074✔
3308
      }
3309
      break;
2,147,483,647✔
3310
    }
3311
  } else {
3312
    int64_t* pts = (int64_t*)pInput->pPTS->pData;
46,265,039✔
3313
    int      from = -1;
46,085,444✔
3314
    int32_t  i = -1;
46,105,674✔
3315
    while (funcInputGetNextRowIndex(pInput, from, false, &i, &from)) {
213,851,674✔
3316
      bool  isNull = colDataIsNull(pInputCol, pInput->numOfRows, i, NULL);
167,741,754✔
3317
      char* data = isNull ? NULL : colDataGetData(pInputCol, i);
167,757,778✔
3318
      TSKEY cts = pts[i];
167,725,757✔
3319

3320
      numOfElems++;
167,748,413✔
3321
      char* pkData = NULL;
167,748,413✔
3322
      if (pCtx->hasPrimaryKey) {
167,748,413✔
3323
        pkData = colDataGetData(pkCol, i);
163,706,620✔
3324
      }
3325
      if (pResInfo->numOfRes == 0 || pInfo->ts < cts ||
167,749,703✔
3326
          (pInfo->ts == pts[i] && pkCompareFn && pkCompareFn(pkData, pInfo->pkData) < 0)) {
157,052,815✔
3327
        int32_t code = doSaveLastrow(pCtx, data, i, cts, pInfo);
10,695,537✔
3328
        if (code != TSDB_CODE_SUCCESS) {
10,698,595✔
UNCOV
3329
          return code;
×
3330
        }
3331
        pResInfo->numOfRes = 1;
10,698,595✔
3332
      }
3333
    }
3334
  }
3335

3336
  SET_VAL(pResInfo, numOfElems, 1);
2,147,483,647✔
3337
  return TSDB_CODE_SUCCESS;
2,147,483,647✔
3338
}
3339

3340
bool getDiffFuncEnv(SFunctionNode* UNUSED_PARAM(pFunc), SFuncExecEnv* pEnv) {
513,943✔
3341
  pEnv->calcMemSize = sizeof(SDiffInfo);
513,943✔
3342
  return true;
513,943✔
3343
}
3344

3345
int32_t diffFunctionSetup(SqlFunctionCtx* pCtx, SResultRowEntryInfo* pResInfo) {
44,039,046✔
3346
  if (pResInfo->initialized) {
44,039,046✔
3347
    return TSDB_CODE_SUCCESS;
38,564,715✔
3348
  }
3349
  if (TSDB_CODE_SUCCESS != functionSetup(pCtx, pResInfo)) {
5,474,331✔
UNCOV
3350
    return TSDB_CODE_FUNC_SETUP_ERROR;
×
3351
  }
3352
  SDiffInfo* pDiffInfo = GET_ROWCELL_INTERBUF(pResInfo);
5,474,331✔
3353
  pDiffInfo->hasPrev = false;
5,474,331✔
3354
  pDiffInfo->isFirstRow = true;
5,474,331✔
3355
  pDiffInfo->prev.i64 = 0;
5,474,331✔
3356
  pDiffInfo->prevTs = -1;
5,474,331✔
3357
  if (pCtx->numOfParams > 1) {
5,474,331✔
3358
    pDiffInfo->ignoreOption = pCtx->param[1].param.i;  // TODO set correct param
5,474,331✔
3359
  } else {
UNCOV
3360
    pDiffInfo->ignoreOption = 0;
×
3361
  }
3362
  return TSDB_CODE_SUCCESS;
5,474,331✔
3363
}
3364

3365
static int32_t doSetPrevVal(SDiffInfo* pDiffInfo, int32_t type, const char* pv, int64_t ts) {
5,373,394✔
3366
  switch (type) {
5,373,394✔
3367
    case TSDB_DATA_TYPE_BOOL:
3,742✔
3368
      pDiffInfo->prev.i64 = *(bool*)pv ? 1 : 0;
3,742✔
3369
      break;
3,742✔
3370
    case TSDB_DATA_TYPE_UTINYINT:
37,698✔
3371
    case TSDB_DATA_TYPE_TINYINT:
3372
      pDiffInfo->prev.i64 = *(int8_t*)pv;
37,698✔
3373
      break;
37,698✔
3374
    case TSDB_DATA_TYPE_UINT:
5,115,194✔
3375
    case TSDB_DATA_TYPE_INT:
3376
      pDiffInfo->prev.i64 = *(int32_t*)pv;
5,115,194✔
3377
      break;
5,115,194✔
3378
    case TSDB_DATA_TYPE_USMALLINT:
39,208✔
3379
    case TSDB_DATA_TYPE_SMALLINT:
3380
      pDiffInfo->prev.i64 = *(int16_t*)pv;
39,208✔
3381
      break;
39,208✔
3382
    case TSDB_DATA_TYPE_TIMESTAMP:
105,256✔
3383
    case TSDB_DATA_TYPE_UBIGINT:
3384
    case TSDB_DATA_TYPE_BIGINT:
3385
      pDiffInfo->prev.i64 = *(int64_t*)pv;
105,256✔
3386
      break;
105,256✔
3387
    case TSDB_DATA_TYPE_FLOAT:
14,862✔
3388
      pDiffInfo->prev.d64 = *(float*)pv;
14,862✔
3389
      break;
14,862✔
3390
    case TSDB_DATA_TYPE_DOUBLE:
57,434✔
3391
      pDiffInfo->prev.d64 = *(double*)pv;
57,434✔
3392
      break;
57,434✔
UNCOV
3393
    default:
×
UNCOV
3394
      return TSDB_CODE_FUNC_FUNTION_PARA_TYPE;
×
3395
  }
3396
  pDiffInfo->prevTs = ts;
5,373,394✔
3397
  pDiffInfo->hasPrev = true;
5,373,394✔
3398
  return TSDB_CODE_SUCCESS;
5,373,394✔
3399
}
3400

3401
static bool diffIsNegtive(SDiffInfo* pDiffInfo, int32_t type, const char* pv) {
2,959,686✔
3402
  switch (type) {
2,959,686✔
3403
    case TSDB_DATA_TYPE_UINT: {
×
3404
      int64_t v = *(uint32_t*)pv;
×
3405
      return v < pDiffInfo->prev.i64;
×
3406
    }
3407
    case TSDB_DATA_TYPE_INT: {
747,714✔
3408
      int64_t v = *(int32_t*)pv;
747,714✔
3409
      return v < pDiffInfo->prev.i64;
747,714✔
3410
    }
UNCOV
3411
    case TSDB_DATA_TYPE_BOOL: {
×
UNCOV
3412
      int64_t v = *(bool*)pv;
×
UNCOV
3413
      return v < pDiffInfo->prev.i64;
×
3414
    }
3415
    case TSDB_DATA_TYPE_UTINYINT: {
×
3416
      int64_t v = *(uint8_t*)pv;
×
3417
      return v < pDiffInfo->prev.i64;
×
3418
    }
3419
    case TSDB_DATA_TYPE_TINYINT: {
776,502✔
3420
      int64_t v = *(int8_t*)pv;
776,502✔
3421
      return v < pDiffInfo->prev.i64;
776,502✔
3422
    }
UNCOV
3423
    case TSDB_DATA_TYPE_USMALLINT: {
×
UNCOV
3424
      int64_t v = *(uint16_t*)pv;
×
UNCOV
3425
      return v < pDiffInfo->prev.i64;
×
3426
    }
3427
    case TSDB_DATA_TYPE_SMALLINT: {
1,033,276✔
3428
      int64_t v = *(int16_t*)pv;
1,033,276✔
3429
      return v < pDiffInfo->prev.i64;
1,033,276✔
3430
    }
3431
    case TSDB_DATA_TYPE_UBIGINT: {
3,328✔
3432
      uint64_t v = *(uint64_t*)pv;
3,328✔
3433
      return v < (uint64_t)pDiffInfo->prev.i64;
3,328✔
3434
    }
3435
    case TSDB_DATA_TYPE_TIMESTAMP:
3,328✔
3436
    case TSDB_DATA_TYPE_BIGINT: {
3437
      int64_t v = *(int64_t*)pv;
3,328✔
3438
      return v < pDiffInfo->prev.i64;
3,328✔
3439
    }
3440
    case TSDB_DATA_TYPE_FLOAT: {
147,324✔
3441
      float v = *(float*)pv;
147,324✔
3442
      return v < pDiffInfo->prev.d64;
147,324✔
3443
    }
3444
    case TSDB_DATA_TYPE_DOUBLE: {
248,214✔
3445
      double v = *(double*)pv;
248,214✔
3446
      return v < pDiffInfo->prev.d64;
248,214✔
3447
    }
UNCOV
3448
    default:
×
UNCOV
3449
      return false;
×
3450
  }
3451

3452
  return false;
3453
}
3454

3455
static void tryToSetInt64(SDiffInfo* pDiffInfo, int32_t type, SColumnInfoData* pOutput, int64_t v, int32_t pos) {
2,147,483,647✔
3456
  bool isNegative = v < pDiffInfo->prev.i64;
2,147,483,647✔
3457
  if (type == TSDB_DATA_TYPE_UBIGINT) {
2,147,483,647✔
3458
    isNegative = (uint64_t)v < (uint64_t)pDiffInfo->prev.i64;
419,592✔
3459
  }
3460
  int64_t delta = v - pDiffInfo->prev.i64;
2,147,483,647✔
3461
  if (isNegative && ignoreNegative(pDiffInfo->ignoreOption)) {
2,147,483,647✔
3462
    colDataSetNull_f_s(pOutput, pos);
1,294,702✔
3463
    pOutput->hasNull = true;
1,294,702✔
3464
  } else {
3465
    colDataSetInt64(pOutput, pos, &delta);
2,147,483,647✔
3466
  }
3467
  pDiffInfo->prev.i64 = v;
2,147,483,647✔
3468
}
2,147,483,647✔
3469

3470
static void tryToSetDouble(SDiffInfo* pDiffInfo, SColumnInfoData* pOutput, double v, int32_t pos) {
27,073,708✔
3471
  double delta = v - pDiffInfo->prev.d64;
27,073,708✔
3472
  if (delta < 0 && ignoreNegative(pDiffInfo->ignoreOption)) {
27,073,708✔
3473
    colDataSetNull_f_s(pOutput, pos);
199,106✔
3474
  } else {
3475
    colDataSetDouble(pOutput, pos, &delta);
26,874,602✔
3476
  }
3477
  pDiffInfo->prev.d64 = v;
27,073,708✔
3478
}
27,073,708✔
3479

3480
static int32_t doHandleDiff(SDiffInfo* pDiffInfo, int32_t type, const char* pv, SColumnInfoData* pOutput, int32_t pos,
2,147,483,647✔
3481
                            int64_t ts) {
3482
  if (!pDiffInfo->hasPrev) {
2,147,483,647✔
3483
    colDataSetNull_f_s(pOutput, pos);
61,831✔
3484
    return doSetPrevVal(pDiffInfo, type, pv, ts);
61,831✔
3485
  }
3486
  pDiffInfo->prevTs = ts;
2,147,483,647✔
3487
  switch (type) {
2,147,483,647✔
3488
    case TSDB_DATA_TYPE_UINT: {
413,768✔
3489
      int64_t v = *(uint32_t*)pv;
413,768✔
3490
      tryToSetInt64(pDiffInfo, type, pOutput, v, pos);
413,768✔
3491
      break;
413,768✔
3492
    }
3493
    case TSDB_DATA_TYPE_INT: {
2,147,483,647✔
3494
      int64_t v = *(int32_t*)pv;
2,147,483,647✔
3495
      tryToSetInt64(pDiffInfo, type, pOutput, v, pos);
2,147,483,647✔
3496
      break;
2,147,483,647✔
3497
    }
3498
    case TSDB_DATA_TYPE_BOOL: {
4,237,338✔
3499
      int64_t v = *(bool*)pv;
4,237,338✔
3500
      tryToSetInt64(pDiffInfo, type, pOutput, v, pos);
4,237,338✔
3501
      break;
4,237,338✔
3502
    }
3503
    case TSDB_DATA_TYPE_UTINYINT: {
56,160✔
3504
      int64_t v = *(uint8_t*)pv;
56,160✔
3505
      tryToSetInt64(pDiffInfo, type, pOutput, v, pos);
56,160✔
3506
      break;
56,160✔
3507
    }
3508
    case TSDB_DATA_TYPE_TINYINT: {
10,141,578✔
3509
      int64_t v = *(int8_t*)pv;
10,141,578✔
3510
      tryToSetInt64(pDiffInfo, type, pOutput, v, pos);
10,141,578✔
3511
      break;
10,141,578✔
3512
    }
3513
    case TSDB_DATA_TYPE_USMALLINT: {
56,160✔
3514
      int64_t v = *(uint16_t*)pv;
56,160✔
3515
      tryToSetInt64(pDiffInfo, type, pOutput, v, pos);
56,160✔
3516
      break;
56,160✔
3517
    }
3518
    case TSDB_DATA_TYPE_SMALLINT: {
9,897,730✔
3519
      int64_t v = *(int16_t*)pv;
9,897,730✔
3520
      tryToSetInt64(pDiffInfo, type, pOutput, v, pos);
9,897,730✔
3521
      break;
9,897,730✔
3522
    }
3523
    case TSDB_DATA_TYPE_TIMESTAMP:
2,147,483,647✔
3524
    case TSDB_DATA_TYPE_UBIGINT:
3525
    case TSDB_DATA_TYPE_BIGINT: {
3526
      int64_t v = *(int64_t*)pv;
2,147,483,647✔
3527
      tryToSetInt64(pDiffInfo, type, pOutput, v, pos);
2,147,483,647✔
3528
      break;
2,147,483,647✔
3529
    }
3530
    case TSDB_DATA_TYPE_FLOAT: {
13,150,166✔
3531
      double v = *(float*)pv;
13,150,166✔
3532
      tryToSetDouble(pDiffInfo, pOutput, v, pos);
13,150,166✔
3533
      break;
13,150,166✔
3534
    }
3535
    case TSDB_DATA_TYPE_DOUBLE: {
13,923,542✔
3536
      double v = *(double*)pv;
13,923,542✔
3537
      tryToSetDouble(pDiffInfo, pOutput, v, pos);
13,923,542✔
3538
      break;
13,923,542✔
3539
    }
UNCOV
3540
    default:
×
UNCOV
3541
      return TSDB_CODE_FUNC_FUNTION_PARA_TYPE;
×
3542
  }
3543
  pDiffInfo->hasPrev = true;
2,147,483,647✔
3544
  return TSDB_CODE_SUCCESS;
2,147,483,647✔
3545
}
3546

3547
// TODO: the primary key compare can be skipped for ordered pk if knonwn before
3548
// TODO: for desc ordered, pk shall select the smallest one for one ts. if across block boundaries.
3549
bool funcInputGetNextRowIndex(SInputColumnInfoData* pInput, int32_t from, bool firstOccur, int32_t* pRowIndex,
2,147,483,647✔
3550
                              int32_t* nextFrom) {
3551
  if (pInput->pPrimaryKey == NULL) {
2,147,483,647✔
3552
    if (from == -1) {
2,147,483,647✔
3553
      from = pInput->startRowIndex;
2,147,483,647✔
3554
    } else if (from >= pInput->numOfRows + pInput->startRowIndex) {
2,147,483,647✔
3555
      return false;
2,147,483,647✔
3556
    }
3557
    *pRowIndex = from;
2,147,483,647✔
3558
    *nextFrom = from + 1;
2,147,483,647✔
3559
    return true;
2,147,483,647✔
3560
  } else {
3561
    if (from == -1) {
626,952,398✔
3562
      from = pInput->startRowIndex;
136,954,323✔
3563
    } else if (from >= pInput->numOfRows + pInput->startRowIndex) {
489,998,075✔
3564
      return false;
137,062,641✔
3565
    }
3566
    TSKEY*           tsList = (int64_t*)pInput->pPTS->pData;
489,967,205✔
3567
    SColumnInfoData* pkCol = pInput->pPrimaryKey;
489,993,427✔
3568
    int8_t           pkType = pkCol->info.type;
490,014,217✔
3569
    int32_t          order = (firstOccur) ? TSDB_ORDER_ASC : TSDB_ORDER_DESC;
490,022,456✔
3570
    __compar_fn_t    compareFunc = getKeyComparFunc(pkType, order);
490,022,456✔
3571
    int32_t          select = from;
489,971,783✔
3572
    char*            val = colDataGetData(pkCol, select);
489,971,783✔
3573
    while (from < pInput->numOfRows + pInput->startRowIndex - 1 && tsList[from + 1] == tsList[from]) {
1,226,877,670✔
3574
      char* val1 = colDataGetData(pkCol, from + 1);
736,916,562✔
3575
      if (compareFunc(val1, val) < 0) {
736,960,543✔
3576
        select = from + 1;
235,400,709✔
3577
        val = val1;
235,400,709✔
3578
      }
3579
      from = from + 1;
736,851,560✔
3580
    }
3581
    *pRowIndex = select;
489,522,334✔
3582
    *nextFrom = from + 1;
490,066,066✔
3583
    return true;
490,069,545✔
3584
  }
3585
}
3586

UNCOV
3587
bool getForecastConfEnv(SFunctionNode* UNUSED_PARAM(pFunc), SFuncExecEnv* pEnv) {
×
UNCOV
3588
  pEnv->calcMemSize = sizeof(double);
×
UNCOV
3589
  return true;
×
3590
}
3591

3592
int32_t diffResultIsNull(SqlFunctionCtx* pCtx, SFuncInputRow* pRow) {
2,147,483,647✔
3593
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
2,147,483,647✔
3594
  SDiffInfo*           pDiffInfo = GET_ROWCELL_INTERBUF(pResInfo);
2,147,483,647✔
3595

3596
  if (pRow->isDataNull || !pDiffInfo->hasPrev) {
2,147,483,647✔
3597
    return true;
12,564,851✔
3598
  } else if (ignoreNegative(pDiffInfo->ignoreOption)) {
2,147,483,647✔
3599
    return diffIsNegtive(pDiffInfo, pCtx->input.pData[0]->info.type, pRow->pData);
2,959,686✔
3600
  }
3601
  return false;
2,147,483,647✔
3602
}
3603

3604
bool isFirstRow(SqlFunctionCtx* pCtx, SFuncInputRow* pRow) {
2,147,483,647✔
3605
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
2,147,483,647✔
3606
  SDiffInfo*           pDiffInfo = GET_ROWCELL_INTERBUF(pResInfo);
2,147,483,647✔
3607
  return pDiffInfo->isFirstRow;
2,147,483,647✔
3608
}
3609

3610
int32_t trySetPreVal(SqlFunctionCtx* pCtx, SFuncInputRow* pRow) {
5,482,125✔
3611
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
5,482,125✔
3612
  SDiffInfo*           pDiffInfo = GET_ROWCELL_INTERBUF(pResInfo);
5,482,125✔
3613
  pDiffInfo->isFirstRow = false;
5,482,125✔
3614
  if (pRow->isDataNull) {
5,482,125✔
3615
    return TSDB_CODE_SUCCESS;
170,562✔
3616
  }
3617

3618
  SInputColumnInfoData* pInput = &pCtx->input;
5,311,563✔
3619
  SColumnInfoData*      pInputCol = pInput->pData[0];
5,311,563✔
3620
  int8_t                inputType = pInputCol->info.type;
5,311,563✔
3621

3622
  char* pv = pRow->pData;
5,311,563✔
3623
  return doSetPrevVal(pDiffInfo, inputType, pv, pRow->ts);
5,311,563✔
3624
}
3625

3626
int32_t setDoDiffResult(SqlFunctionCtx* pCtx, SFuncInputRow* pRow, int32_t pos) {
2,147,483,647✔
3627
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
2,147,483,647✔
3628
  SDiffInfo*           pDiffInfo = GET_ROWCELL_INTERBUF(pResInfo);
2,147,483,647✔
3629

3630
  SInputColumnInfoData* pInput = &pCtx->input;
2,147,483,647✔
3631
  SColumnInfoData*      pInputCol = pInput->pData[0];
2,147,483,647✔
3632
  int8_t                inputType = pInputCol->info.type;
2,147,483,647✔
3633
  SColumnInfoData*      pOutput = (SColumnInfoData*)pCtx->pOutput;
2,147,483,647✔
3634
  int32_t               code = TSDB_CODE_SUCCESS;
2,147,483,647✔
3635
  if (pRow->isDataNull) {
2,147,483,647✔
3636
    colDataSetNull_f_s(pOutput, pos);
7,027,967✔
3637
    pOutput->hasNull = true;
7,027,967✔
3638

3639
    // handle selectivity
3640
    if (pCtx->subsidiaries.num > 0) {
7,027,967✔
3641
      code = appendSelectivityCols(pCtx, pRow->block, pRow->rowIndex, pos);
19,964✔
3642
      if (code != TSDB_CODE_SUCCESS) {
19,964✔
UNCOV
3643
        return code;
×
3644
      }
3645
    }
3646
    return TSDB_CODE_SUCCESS;
7,027,967✔
3647
  }
3648

3649
  char* pv = pRow->pData;
2,147,483,647✔
3650

3651
  if (pRow->ts == pDiffInfo->prevTs) {
2,147,483,647✔
3652
    return TSDB_CODE_FUNC_DUP_TIMESTAMP;
7,530✔
3653
  }
3654
  code = doHandleDiff(pDiffInfo, inputType, pv, pOutput, pos, pRow->ts);
2,147,483,647✔
3655
  if (code != TSDB_CODE_SUCCESS) {
2,147,483,647✔
UNCOV
3656
    return code;
×
3657
  }
3658
  // handle selectivity
3659
  if (pCtx->subsidiaries.num > 0) {
2,147,483,647✔
3660
    code = appendSelectivityCols(pCtx, pRow->block, pRow->rowIndex, pos);
2,147,483,647✔
3661
    if (code != TSDB_CODE_SUCCESS) {
2,147,483,647✔
UNCOV
3662
      return code;
×
3663
    }
3664
  }
3665

3666
  return TSDB_CODE_SUCCESS;
2,147,483,647✔
3667
}
3668

3669
int32_t diffFunction(SqlFunctionCtx* pCtx) { return TSDB_CODE_SUCCESS; }
43,525,103✔
3670

3671
int32_t diffFunctionByRow(SArray* pCtxArray) {
43,502,639✔
3672
  int32_t code = TSDB_CODE_SUCCESS;
43,502,639✔
3673
  int     diffColNum = pCtxArray->size;
43,502,639✔
3674
  if (diffColNum == 0) {
43,502,639✔
UNCOV
3675
    return TSDB_CODE_SUCCESS;
×
3676
  }
3677
  int32_t numOfElems = 0;
43,502,639✔
3678

3679
  SArray* pRows = taosArrayInit_s(sizeof(SFuncInputRow), diffColNum);
43,502,639✔
3680
  if (NULL == pRows) {
43,502,639✔
3681
    return terrno;
×
3682
  }
3683

3684
  bool keepNull = false;
43,502,639✔
3685
  for (int i = 0; i < diffColNum; ++i) {
87,027,742✔
3686
    SqlFunctionCtx* pCtx = *(SqlFunctionCtx**)taosArrayGet(pCtxArray, i);
43,525,103✔
3687
    if (NULL == pCtx) {
43,525,103✔
UNCOV
3688
      code = terrno;
×
UNCOV
3689
      goto _exit;
×
3690
    }
3691
    funcInputUpdate(pCtx);
43,525,103✔
3692
    SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
43,525,103✔
3693
    SDiffInfo*           pDiffInfo = GET_ROWCELL_INTERBUF(pResInfo);
43,525,103✔
3694
    if (!ignoreNull(pDiffInfo->ignoreOption)) {
43,525,103✔
3695
      keepNull = true;
43,508,047✔
3696
    }
3697
  }
3698

3699
  SqlFunctionCtx* pCtx0 = *(SqlFunctionCtx**)taosArrayGet(pCtxArray, 0);
43,502,639✔
3700
  SFuncInputRow*  pRow0 = (SFuncInputRow*)taosArrayGet(pRows, 0);
43,502,639✔
3701
  if (NULL == pCtx0 || NULL == pRow0) {
43,502,639✔
3702
    code = terrno;
×
UNCOV
3703
    goto _exit;
×
3704
  }
3705
  int32_t startOffset = pCtx0->offset;
43,502,639✔
3706
  bool    result = false;
43,502,639✔
3707
  while (1) {
2,147,483,647✔
3708
    code = funcInputGetNextRow(pCtx0, pRow0, &result);
2,147,483,647✔
3709
    if (TSDB_CODE_SUCCESS != code) {
2,147,483,647✔
UNCOV
3710
      goto _exit;
×
3711
    }
3712
    if (!result) {
2,147,483,647✔
3713
      break;
43,495,109✔
3714
    }
3715
    bool hasNotNullValue = !diffResultIsNull(pCtx0, pRow0);
2,147,483,647✔
3716
    for (int i = 1; i < diffColNum; ++i) {
2,147,483,647✔
3717
      SqlFunctionCtx* pCtx = *(SqlFunctionCtx**)taosArrayGet(pCtxArray, i);
4,783,168✔
3718
      SFuncInputRow*  pRow = (SFuncInputRow*)taosArrayGet(pRows, i);
4,783,168✔
3719
      if (NULL == pCtx || NULL == pRow) {
4,783,168✔
UNCOV
3720
        code = terrno;
×
3721
        goto _exit;
×
3722
      }
3723
      code = funcInputGetNextRow(pCtx, pRow, &result);
4,783,168✔
3724
      if (TSDB_CODE_SUCCESS != code) {
4,783,168✔
UNCOV
3725
        goto _exit;
×
3726
      }
3727
      if (!result) {
4,783,168✔
3728
        // rows are not equal
UNCOV
3729
        code = TSDB_CODE_QRY_EXECUTOR_INTERNAL_ERROR;
×
UNCOV
3730
        goto _exit;
×
3731
      }
3732
      if (!diffResultIsNull(pCtx, pRow)) {
4,783,168✔
3733
        hasNotNullValue = true;
4,721,600✔
3734
      }
3735
    }
3736
    int32_t pos = startOffset + numOfElems;
2,147,483,647✔
3737

3738
    bool newRow = false;
2,147,483,647✔
3739
    for (int i = 0; i < diffColNum; ++i) {
2,147,483,647✔
3740
      SqlFunctionCtx* pCtx = *(SqlFunctionCtx**)taosArrayGet(pCtxArray, i);
2,147,483,647✔
3741
      SFuncInputRow*  pRow = (SFuncInputRow*)taosArrayGet(pRows, i);
2,147,483,647✔
3742
      if (NULL == pCtx || NULL == pRow) {
2,147,483,647✔
UNCOV
3743
        code = terrno;
×
UNCOV
3744
        goto _exit;
×
3745
      }
3746
      if ((keepNull || hasNotNullValue) && !isFirstRow(pCtx, pRow)) {
2,147,483,647✔
3747
        code = setDoDiffResult(pCtx, pRow, pos);
2,147,483,647✔
3748
        if (code != TSDB_CODE_SUCCESS) {
2,147,483,647✔
3749
          goto _exit;
7,530✔
3750
        }
3751
        newRow = true;
2,147,483,647✔
3752
      } else {
3753
        code = trySetPreVal(pCtx, pRow);
5,482,125✔
3754
        if (code != TSDB_CODE_SUCCESS) {
5,482,125✔
UNCOV
3755
          goto _exit;
×
3756
        }
3757
      }
3758
    }
3759
    if (newRow) ++numOfElems;
2,147,483,647✔
3760
  }
3761

3762
  for (int i = 0; i < diffColNum; ++i) {
87,012,266✔
3763
    SqlFunctionCtx* pCtx = *(SqlFunctionCtx**)taosArrayGet(pCtxArray, i);
43,517,157✔
3764
    if (NULL == pCtx) {
43,517,157✔
UNCOV
3765
      code = terrno;
×
UNCOV
3766
      goto _exit;
×
3767
    }
3768
    SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
43,517,157✔
3769
    pResInfo->numOfRes = numOfElems;
43,517,157✔
3770
  }
3771

3772
_exit:
43,502,639✔
3773
  if (pRows) {
43,502,639✔
3774
    taosArrayDestroy(pRows);
43,502,639✔
3775
    pRows = NULL;
43,502,639✔
3776
  }
3777
  return code;
43,502,639✔
3778
}
3779

3780
bool getFillforwardFuncEnv(SFunctionNode* UNUSED_PARAM(pFunc), SFuncExecEnv* pEnv) {
34,412✔
3781
  pEnv->calcMemSize = sizeof(SFillforwardInfo);
34,412✔
3782
  return true;
34,412✔
3783
}
3784

3785
int32_t fillforwardFunctionSetup(SqlFunctionCtx* pCtx, SResultRowEntryInfo* pResInfo) {
71,284✔
3786
  if (pResInfo->initialized) {
71,284✔
3787
    return TSDB_CODE_SUCCESS;
34,412✔
3788
  }
3789
  if (TSDB_CODE_SUCCESS != functionSetup(pCtx, pResInfo)) {
36,872✔
UNCOV
3790
    return TSDB_CODE_FUNC_SETUP_ERROR;
×
3791
  }
3792
  SFillforwardInfo* pFillforwardInfo = GET_ROWCELL_INTERBUF(pResInfo);
36,872✔
3793
  pFillforwardInfo->nonnull = false;
36,872✔
3794

3795
  return TSDB_CODE_SUCCESS;
36,872✔
3796
}
3797

3798
int32_t fillforwardFunction(SqlFunctionCtx* pCtx) { return TSDB_CODE_SUCCESS; }
36,872✔
3799

3800
static int32_t doHandleFillforward(SFillforwardInfo* pFillforwardInfo, int32_t type, SColumnInfoData* pOutput, int32_t pos) {
119,608✔
3801
  if (!pFillforwardInfo->nonnull) {
119,608✔
3802
    colDataSetNULL(pOutput, pos);
13,530✔
3803

3804
    return TSDB_CODE_SUCCESS;
13,530✔
3805
  }
3806

3807
  switch (type) {
106,078✔
3808
    case TSDB_DATA_TYPE_BOOL:
51,138✔
3809
    case TSDB_DATA_TYPE_UTINYINT:
3810
    case TSDB_DATA_TYPE_TINYINT:
3811
    case TSDB_DATA_TYPE_USMALLINT:
3812
    case TSDB_DATA_TYPE_SMALLINT:
3813
    case TSDB_DATA_TYPE_UINT:
3814
    case TSDB_DATA_TYPE_INT:
3815
    case TSDB_DATA_TYPE_UBIGINT:
3816
    case TSDB_DATA_TYPE_BIGINT:
3817
    case TSDB_DATA_TYPE_TIMESTAMP:
3818
      colDataSetInt64(pOutput, pos, &pFillforwardInfo->v);
51,138✔
3819
      break;
51,138✔
3820
    case TSDB_DATA_TYPE_FLOAT:
19,680✔
3821
      colDataSetFloat(pOutput, pos, &pFillforwardInfo->fv);
19,680✔
3822
      break;
19,680✔
3823
    case TSDB_DATA_TYPE_DOUBLE:
22,140✔
3824
      colDataSetDouble(pOutput, pos, &pFillforwardInfo->dv);
22,140✔
3825
      break;
22,140✔
3826
    case TSDB_DATA_TYPE_DECIMAL64:
4,510✔
3827
      return colDataSetVal(pOutput, pos, (const char*)&pFillforwardInfo->v, false);
4,510✔
UNCOV
3828
    case TSDB_DATA_TYPE_DECIMAL:
×
UNCOV
3829
      return colDataSetVal(pOutput, pos, (void*)pFillforwardInfo->dec, false);
×
3830
    case TSDB_DATA_TYPE_VARCHAR:
8,610✔
3831
    case TSDB_DATA_TYPE_VARBINARY:
3832
    case TSDB_DATA_TYPE_NCHAR:
3833
      return colDataSetVal(pOutput, pos, (void*)pFillforwardInfo->str, false);
8,610✔
UNCOV
3834
    default:
×
UNCOV
3835
      return TSDB_CODE_FUNC_FUNTION_PARA_TYPE;
×
3836
  }
3837

3838
  return TSDB_CODE_SUCCESS;
92,958✔
3839
}
3840

3841
static int32_t setFillforwardResult(SqlFunctionCtx* pCtx, SFuncInputRow* pRow, int32_t pos) {
119,608✔
3842
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
119,608✔
3843
  SFillforwardInfo*            pFillforwardInfo = GET_ROWCELL_INTERBUF(pResInfo);
119,608✔
3844

3845
  SInputColumnInfoData* pInput = &pCtx->input;
119,608✔
3846
  SColumnInfoData*      pInputCol = pInput->pData[0];
119,608✔
3847
  int8_t                inputType = pInputCol->info.type;
119,608✔
3848
  SColumnInfoData*      pOutput = (SColumnInfoData*)pCtx->pOutput;
119,608✔
3849
  int32_t               code = TSDB_CODE_SUCCESS;
119,608✔
3850

3851
  code = doHandleFillforward(pFillforwardInfo, inputType, pOutput, pos);
119,608✔
3852
  if (code != TSDB_CODE_SUCCESS) {
119,608✔
UNCOV
3853
    return code;
×
3854
  }
3855

3856
  // handle selectivity
3857
  if (pCtx->subsidiaries.num > 0) {
119,608✔
3858
    code = appendSelectivityCols(pCtx, pRow->block, pRow->rowIndex, pos);
32,688✔
3859
    if (code != TSDB_CODE_SUCCESS) {
32,688✔
UNCOV
3860
      return code;
×
3861
    }
3862
  }
3863

3864
  return TSDB_CODE_SUCCESS;
119,608✔
3865
}
3866

3867
int32_t fillforwardFunctionByRow(SArray* pCtxArray) {
10,632✔
3868
  int32_t code = TSDB_CODE_SUCCESS;
10,632✔
3869
  int     fillforwardColNum = pCtxArray->size;
10,632✔
3870
  if (fillforwardColNum == 0) {
10,632✔
UNCOV
3871
    return TSDB_CODE_SUCCESS;
×
3872
  }
3873
  int32_t numOfElems = 0;
10,632✔
3874

3875
  SArray* pRows = taosArrayInit_s(sizeof(SFuncInputRow), fillforwardColNum);
10,632✔
3876
  if (NULL == pRows) {
10,632✔
UNCOV
3877
    return terrno;
×
3878
  }
3879

3880
  for (int i = 0; i < fillforwardColNum; ++i) {
47,504✔
3881
    SqlFunctionCtx* pCtx = *(SqlFunctionCtx**)taosArrayGet(pCtxArray, i);
36,872✔
3882
    if (NULL == pCtx) {
36,872✔
UNCOV
3883
      code = terrno;
×
3884
      goto _exit;
×
3885
    }
3886
    funcInputUpdate(pCtx);
36,872✔
3887
  }
3888

3889
  SqlFunctionCtx* pCtx0 = *(SqlFunctionCtx**)taosArrayGet(pCtxArray, 0);
10,632✔
3890
  SFuncInputRow*  pRow0 = (SFuncInputRow*)taosArrayGet(pRows, 0);
10,632✔
3891
  if (NULL == pCtx0 || NULL == pRow0) {
10,632✔
3892
    code = terrno;
×
UNCOV
3893
    goto _exit;
×
3894
  }
3895
  int32_t startOffset = pCtx0->offset;
10,632✔
3896
  bool    result = false;
10,632✔
3897
  while (1) {
32,688✔
3898
    code = funcInputGetNextRow(pCtx0, pRow0, &result);
43,320✔
3899
    if (TSDB_CODE_SUCCESS != code) {
43,320✔
UNCOV
3900
      goto _exit;
×
3901
    }
3902
    if (!result) {
43,320✔
3903
      break;
10,222✔
3904
    }
3905

3906
    for (int i = 1; i < fillforwardColNum; ++i) {
120,018✔
3907
      SqlFunctionCtx* pCtx = *(SqlFunctionCtx**)taosArrayGet(pCtxArray, i);
86,920✔
3908
      SFuncInputRow*  pRow = (SFuncInputRow*)taosArrayGet(pRows, i);
86,920✔
3909
      if (NULL == pCtx || NULL == pRow) {
86,920✔
UNCOV
3910
        code = terrno;
×
3911
        goto _exit;
×
3912
      }
3913
      code = funcInputGetNextRow(pCtx, pRow, &result);
86,920✔
3914
      if (TSDB_CODE_SUCCESS != code) {
86,920✔
UNCOV
3915
        goto _exit;
×
3916
      }
3917
      if (!result) {
86,920✔
3918
        // rows are not equal
UNCOV
3919
        code = TSDB_CODE_QRY_EXECUTOR_INTERNAL_ERROR;
×
UNCOV
3920
        goto _exit;
×
3921
      }
3922
    }
3923

3924
    int32_t pos = startOffset + numOfElems;
33,098✔
3925

3926
    for (int i = 0; i < fillforwardColNum; ++i) {
152,706✔
3927
      SqlFunctionCtx* pCtx = *(SqlFunctionCtx**)taosArrayGet(pCtxArray, i);
120,018✔
3928
      SFuncInputRow*  pRow = (SFuncInputRow*)taosArrayGet(pRows, i);
120,018✔
3929
      if (NULL == pCtx || NULL == pRow) {
120,018✔
UNCOV
3930
        code = terrno;
×
UNCOV
3931
        goto _exit;
×
3932
      }
3933

3934
      if (!colDataIsNull_s(pCtx->input.pData[0], pCtx->rowIter.rowIndex - 1)) {
240,036✔
3935
        SResultRowEntryInfo*  pResInfo = GET_RES_INFO(pCtx);
73,688✔
3936
        SFillforwardInfo*             pFillforwardInfo = GET_ROWCELL_INTERBUF(pResInfo);
73,688✔
3937
        SInputColumnInfoData* pInput = &pCtx->input;
73,688✔
3938
        SColumnInfoData*      pInputCol = pInput->pData[0];
73,688✔
3939
        int8_t                inputType = pInputCol->info.type;
73,688✔
3940

3941
        char* pv = pRow->pData;
73,688✔
3942
        switch (inputType) {
73,688✔
3943
          case TSDB_DATA_TYPE_BOOL:
14,350✔
3944
            pFillforwardInfo->v = *(bool*)pv ? 1 : 0;
14,350✔
3945
            break;
14,350✔
3946
          case TSDB_DATA_TYPE_UTINYINT:
410✔
3947
          case TSDB_DATA_TYPE_TINYINT:
3948
            pFillforwardInfo->v = *(int8_t*)pv;
410✔
3949
            break;
410✔
3950
          case TSDB_DATA_TYPE_UINT:
21,208✔
3951
          case TSDB_DATA_TYPE_INT:
3952
            pFillforwardInfo->v = *(int32_t*)pv;
21,208✔
3953
            break;
21,208✔
3954
          case TSDB_DATA_TYPE_USMALLINT:
410✔
3955
          case TSDB_DATA_TYPE_SMALLINT:
3956
            pFillforwardInfo->v = *(int16_t*)pv;
410✔
3957
            break;
410✔
3958
          case TSDB_DATA_TYPE_TIMESTAMP:
410✔
3959
          case TSDB_DATA_TYPE_UBIGINT:
3960
          case TSDB_DATA_TYPE_BIGINT:
3961
            pFillforwardInfo->v = *(int64_t*)pv;
410✔
3962
            break;
410✔
3963
          case TSDB_DATA_TYPE_FLOAT:
14,350✔
3964
            pFillforwardInfo->fv = *(float*)pv;
14,350✔
3965
            break;
14,350✔
3966
          case TSDB_DATA_TYPE_DOUBLE:
15,990✔
3967
            pFillforwardInfo->dv = *(double*)pv;
15,990✔
3968
            break;
15,990✔
3969
          case TSDB_DATA_TYPE_DECIMAL64:
2,460✔
3970
            DECIMAL64_SET_VALUE((Decimal64*)&pFillforwardInfo->v, *(int64_t*)pv);
2,460✔
3971
            break;
2,460✔
UNCOV
3972
          case TSDB_DATA_TYPE_DECIMAL:
×
3973
            DECIMAL128_CLONE((Decimal128*)pFillforwardInfo->dec, (Decimal128*)pv);
×
3974
            break;
×
3975
          case TSDB_DATA_TYPE_VARCHAR:
3,690✔
3976
          case TSDB_DATA_TYPE_VARBINARY:
3977
          case TSDB_DATA_TYPE_NCHAR: {
3978
            if (!pFillforwardInfo->nonnull) {
3,690✔
3979
              pFillforwardInfo->str = taosMemoryMalloc(pInputCol->info.bytes);
2,460✔
3980
              if (!pFillforwardInfo->str) {
2,460✔
UNCOV
3981
                code = terrno;
×
UNCOV
3982
                goto _exit;
×
3983
              }
3984
            }
3985

3986
            (void)memcpy(pFillforwardInfo->str, pv, varDataTLen(pv));
3,690✔
3987
          } break;
3,690✔
3988
          default: {
410✔
3989
            code = TSDB_CODE_FUNC_FUNTION_PARA_TYPE;
410✔
3990
            goto _exit;
410✔
3991
          }
3992
        }
3993

3994
        if (!pFillforwardInfo->nonnull) {
73,278✔
3995
          pFillforwardInfo->nonnull = true;
36,052✔
3996
        }
3997
      }
3998

3999
      code = setFillforwardResult(pCtx, pRow, pos);
119,608✔
4000
      if (code) {
119,608✔
UNCOV
4001
        goto _exit;
×
4002
      }
4003
    }
4004

4005
    ++numOfElems;
32,688✔
4006
  }
4007

4008
_exit:
10,632✔
4009
  for (int i = 0; i < fillforwardColNum; ++i) {
47,504✔
4010
    SqlFunctionCtx* pCtx = *(SqlFunctionCtx**)taosArrayGet(pCtxArray, i);
36,872✔
4011
    if (!pCtx) {
36,872✔
UNCOV
4012
      break;
×
4013
    }
4014

4015
    SResultRowEntryInfo*  pResInfo = GET_RES_INFO(pCtx);
36,872✔
4016
    SFillforwardInfo*             pRes = GET_ROWCELL_INTERBUF(pResInfo);
36,872✔
4017
    SInputColumnInfoData* pInput = &pCtx->input;
36,872✔
4018
    SColumnInfoData*      pInputCol = pInput->pData[0];
36,872✔
4019

4020
    if (IS_VAR_DATA_TYPE(pInputCol->info.type) && pRes->nonnull) {
36,872✔
4021
      taosMemoryFree(pRes->str);
2,460✔
4022
    }
4023

4024
    if (!code) {
36,872✔
4025
      pResInfo->numOfRes = numOfElems;
36,462✔
4026
    }
4027
  }
4028

4029
  if (pRows) {
10,632✔
4030
    taosArrayDestroy(pRows);
10,632✔
4031
    pRows = NULL;
10,632✔
4032
  }
4033
  return code;
10,632✔
4034
}
4035

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

4038
bool getTopBotFuncEnv(SFunctionNode* pFunc, SFuncExecEnv* pEnv) {
2,227,406✔
4039
  SValueNode* pkNode = (SValueNode*)nodesListGetNode(pFunc->pParameterList, 1);
2,227,406✔
4040
  pEnv->calcMemSize = sizeof(STopBotRes) + pkNode->datum.i * sizeof(STopBotResItem);
2,226,601✔
4041
  return true;
2,227,001✔
4042
}
4043

4044
int32_t topBotFunctionSetup(SqlFunctionCtx* pCtx, SResultRowEntryInfo* pResInfo) {
7,784,356✔
4045
  if (pResInfo->initialized) {
7,784,356✔
UNCOV
4046
    return TSDB_CODE_SUCCESS;
×
4047
  }
4048
  if (TSDB_CODE_SUCCESS != functionSetup(pCtx, pResInfo)) {
7,785,560✔
UNCOV
4049
    return TSDB_CODE_FUNC_SETUP_ERROR;
×
4050
  }
4051

4052
  STopBotRes*           pRes = GET_ROWCELL_INTERBUF(pResInfo);
7,784,449✔
4053
  SInputColumnInfoData* pInput = &pCtx->input;
7,784,651✔
4054

4055
  pRes->maxSize = pCtx->param[1].param.i;
7,784,651✔
4056

4057
  pRes->nullTupleSaved = false;
7,783,649✔
4058
  pRes->nullTuplePos.pageId = -1;
7,784,049✔
4059
  return TSDB_CODE_SUCCESS;
7,782,938✔
4060
}
4061

4062
static STopBotRes* getTopBotOutputInfo(SqlFunctionCtx* pCtx) {
2,147,483,647✔
4063
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
2,147,483,647✔
4064
  STopBotRes*          pRes = GET_ROWCELL_INTERBUF(pResInfo);
2,147,483,647✔
4065
  pRes->pItems = (STopBotResItem*)((char*)pRes + sizeof(STopBotRes));
2,147,483,647✔
4066

4067
  return pRes;
2,147,483,647✔
4068
}
4069

4070
static int32_t doAddIntoResult(SqlFunctionCtx* pCtx, void* pData, int32_t rowIndex, SSDataBlock* pSrcBlock,
4071
                               uint16_t type, uint64_t uid, SResultRowEntryInfo* pEntryInfo, bool isTopQuery);
4072

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

4075
int32_t topFunction(SqlFunctionCtx* pCtx) {
8,971,879✔
4076
  int32_t              numOfElems = 0;
8,971,879✔
4077
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
8,971,879✔
4078

4079
  SInputColumnInfoData* pInput = &pCtx->input;
8,977,978✔
4080
  SColumnInfoData*      pCol = pInput->pData[0];
8,977,978✔
4081

4082
  STopBotRes* pRes = getTopBotOutputInfo(pCtx);
8,977,978✔
4083
  pRes->type = pInput->pData[0]->info.type;
8,976,332✔
4084

4085
  int32_t start = pInput->startRowIndex;
8,977,902✔
4086
  for (int32_t i = start; i < pInput->numOfRows + start; ++i) {
2,147,483,647✔
4087
    if (pCol->hasNull && colDataIsNull_f(pCol, i)) {
2,147,483,647✔
4088
      continue;
2,322,683✔
4089
    }
4090

4091
    numOfElems++;
2,147,483,647✔
4092
    char*   data = colDataGetData(pCol, i);
2,147,483,647✔
4093
    int32_t code = doAddIntoResult(pCtx, data, i, pCtx->pSrcBlock, pRes->type, pInput->uid, pResInfo, true);
2,147,483,647✔
4094
    if (code != TSDB_CODE_SUCCESS) {
2,147,483,647✔
UNCOV
4095
      return code;
×
4096
    }
4097
  }
4098

4099
  if (numOfElems == 0 && pCtx->subsidiaries.num > 0 && !pRes->nullTupleSaved) {
8,979,072✔
4100
    int32_t code = saveTupleData(pCtx, pInput->startRowIndex, pCtx->pSrcBlock, &pRes->nullTuplePos);
7,446✔
4101
    if (code != TSDB_CODE_SUCCESS) {
7,446✔
UNCOV
4102
      return code;
×
4103
    }
4104
    pRes->nullTupleSaved = true;
7,446✔
4105
  }
4106
  return TSDB_CODE_SUCCESS;
8,977,670✔
4107
}
4108

4109
int32_t bottomFunction(SqlFunctionCtx* pCtx) {
3,476,500✔
4110
  int32_t              numOfElems = 0;
3,476,500✔
4111
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
3,476,500✔
4112

4113
  SInputColumnInfoData* pInput = &pCtx->input;
3,476,500✔
4114
  SColumnInfoData*      pCol = pInput->pData[0];
3,476,500✔
4115

4116
  STopBotRes* pRes = getTopBotOutputInfo(pCtx);
3,477,102✔
4117
  pRes->type = pInput->pData[0]->info.type;
3,476,517✔
4118

4119
  int32_t start = pInput->startRowIndex;
3,476,517✔
4120
  for (int32_t i = start; i < pInput->numOfRows + start; ++i) {
1,839,115,539✔
4121
    if (pCol->hasNull && colDataIsNull_f(pCol, i)) {
1,836,223,101✔
4122
      continue;
3,297,335✔
4123
    }
4124

4125
    numOfElems++;
1,831,270,829✔
4126
    char*   data = colDataGetData(pCol, i);
1,831,270,829✔
4127
    int32_t code = doAddIntoResult(pCtx, data, i, pCtx->pSrcBlock, pRes->type, pInput->uid, pResInfo, false);
1,833,324,780✔
4128
    if (code != TSDB_CODE_SUCCESS) {
1,832,341,102✔
UNCOV
4129
      return code;
×
4130
    }
4131
  }
4132

4133
  if (numOfElems == 0 && pCtx->subsidiaries.num > 0 && !pRes->nullTupleSaved) {
3,476,500✔
4134
    int32_t code = saveTupleData(pCtx, pInput->startRowIndex, pCtx->pSrcBlock, &pRes->nullTuplePos);
10,414✔
4135
    if (code != TSDB_CODE_SUCCESS) {
10,414✔
UNCOV
4136
      return code;
×
4137
    }
4138
    pRes->nullTupleSaved = true;
10,414✔
4139
  }
4140

4141
  return TSDB_CODE_SUCCESS;
3,476,500✔
4142
}
4143

4144
static int32_t topBotResComparFn(const void* p1, const void* p2, const void* param) {
488,704,506✔
4145
  uint16_t type = *(uint16_t*)param;
488,704,506✔
4146

4147
  STopBotResItem* val1 = (STopBotResItem*)p1;
488,713,729✔
4148
  STopBotResItem* val2 = (STopBotResItem*)p2;
488,713,729✔
4149

4150
  if (IS_SIGNED_NUMERIC_TYPE(type)) {
488,713,729✔
4151
    if (val1->v.i == val2->v.i) {
307,338,584✔
4152
      return 0;
59,004,840✔
4153
    }
4154

4155
    return (val1->v.i > val2->v.i) ? 1 : -1;
248,447,203✔
4156
  } else if (IS_UNSIGNED_NUMERIC_TYPE(type)) {
181,375,145✔
4157
    if (val1->v.u == val2->v.u) {
93,979,311✔
4158
      return 0;
19,643,690✔
4159
    }
4160

4161
    return (val1->v.u > val2->v.u) ? 1 : -1;
74,345,407✔
4162
  } else if (TSDB_DATA_TYPE_FLOAT == type) {
87,395,989✔
4163
    if (val1->v.f == val2->v.f) {
2,182,107✔
4164
      return 0;
26,145✔
4165
    }
4166

4167
    return (val1->v.f > val2->v.f) ? 1 : -1;
2,155,962✔
4168
  }
4169

4170
  if (val1->v.d == val2->v.d) {
85,213,882✔
4171
    return 0;
4,565✔
4172
  }
4173

4174
  return (val1->v.d > val2->v.d) ? 1 : -1;
85,221,176✔
4175
}
4176

4177
int32_t doAddIntoResult(SqlFunctionCtx* pCtx, void* pData, int32_t rowIndex, SSDataBlock* pSrcBlock, uint16_t type,
2,147,483,647✔
4178
                        uint64_t uid, SResultRowEntryInfo* pEntryInfo, bool isTopQuery) {
4179
  STopBotRes* pRes = getTopBotOutputInfo(pCtx);
2,147,483,647✔
4180
  int32_t     code = TSDB_CODE_SUCCESS;
2,147,483,647✔
4181

4182
  SVariant val = {0};
2,147,483,647✔
4183
  TAOS_CHECK_RETURN(taosVariantCreateFromBinary(&val, pData, tDataTypes[type].bytes, type));
2,147,483,647✔
4184

4185
  STopBotResItem* pItems = pRes->pItems;
2,147,483,647✔
4186

4187
  // not full yet
4188
  if (pEntryInfo->numOfRes < pRes->maxSize) {
2,147,483,647✔
4189
    STopBotResItem* pItem = &pItems[pEntryInfo->numOfRes];
45,157,280✔
4190
    pItem->v = val;
45,157,280✔
4191
    pItem->uid = uid;
45,158,282✔
4192

4193
    // save the data of this tuple
4194
    if (pCtx->subsidiaries.num > 0) {
45,156,639✔
4195
      code = saveTupleData(pCtx, rowIndex, pSrcBlock, &pItem->tuplePos);
11,642,333✔
4196
      if (code != TSDB_CODE_SUCCESS) {
11,641,933✔
UNCOV
4197
        return code;
×
4198
      }
4199
    }
4200
#ifdef BUF_PAGE_DEBUG
4201
    qDebug("page_saveTuple i:%d, item:%p,pageId:%d, offset:%d\n", pEntryInfo->numOfRes, pItem, pItem->tuplePos.pageId,
4202
           pItem->tuplePos.offset);
4203
#endif
4204
    // allocate the buffer and keep the data of this row into the new allocated buffer
4205
    pEntryInfo->numOfRes++;
45,156,278✔
4206
    code = taosheapsort((void*)pItems, sizeof(STopBotResItem), pEntryInfo->numOfRes, (const void*)&type,
45,156,984✔
4207
                        topBotResComparFn, !isTopQuery);
45,156,984✔
4208
    if (code != TSDB_CODE_SUCCESS) {
45,154,657✔
UNCOV
4209
      return code;
×
4210
    }
4211
  } else {  // replace the minimum value in the result
4212
    if ((isTopQuery && ((IS_SIGNED_NUMERIC_TYPE(type) && val.i > pItems[0].v.i) ||
2,147,483,647✔
4213
                        (IS_UNSIGNED_NUMERIC_TYPE(type) && val.u > pItems[0].v.u) ||
2,147,483,647✔
4214
                        (TSDB_DATA_TYPE_FLOAT == type && val.f > pItems[0].v.f) ||
2,147,483,647✔
4215
                        (TSDB_DATA_TYPE_DOUBLE == type && val.d > pItems[0].v.d))) ||
2,147,483,647✔
4216
        (!isTopQuery && ((IS_SIGNED_NUMERIC_TYPE(type) && val.i < pItems[0].v.i) ||
2,147,483,647✔
4217
                         (IS_UNSIGNED_NUMERIC_TYPE(type) && val.u < pItems[0].v.u) ||
1,821,270,938✔
4218
                         (TSDB_DATA_TYPE_FLOAT == type && val.f < pItems[0].v.f) ||
1,819,379,105✔
4219
                         (TSDB_DATA_TYPE_DOUBLE == type && val.d < pItems[0].v.d)))) {
1,818,993,640✔
4220
      // replace the old data and the coresponding tuple data
4221
      STopBotResItem* pItem = &pItems[0];
37,037,626✔
4222
      pItem->v = val;
37,037,626✔
4223
      pItem->uid = uid;
37,341,803✔
4224

4225
      // save the data of this tuple by over writing the old data
4226
      if (pCtx->subsidiaries.num > 0) {
37,343,112✔
4227
        code = updateTupleData(pCtx, rowIndex, pSrcBlock, &pItem->tuplePos);
18,744,029✔
4228
        if (code != TSDB_CODE_SUCCESS) {
18,743,629✔
UNCOV
4229
          return code;
×
4230
        }
4231
      }
4232
#ifdef BUF_PAGE_DEBUG
4233
      qDebug("page_copyTuple pageId:%d, offset:%d", pItem->tuplePos.pageId, pItem->tuplePos.offset);
4234
#endif
4235
      code = taosheapadjust((void*)pItems, sizeof(STopBotResItem), 0, pEntryInfo->numOfRes - 1, (const void*)&type,
37,340,715✔
4236
                            topBotResComparFn, NULL, !isTopQuery);
37,342,421✔
4237
      if (code != TSDB_CODE_SUCCESS) {
37,343,023✔
UNCOV
4238
        return code;
×
4239
      }
4240
    }
4241
  }
4242

4243
  return TSDB_CODE_SUCCESS;
2,147,483,647✔
4244
}
4245

4246

UNCOV
4247
bool hasNullFunc(  SColumnInfoData *pData,   SColumnDataAgg *pAgg, int32_t startIdx, int64_t rows) {
×
UNCOV
4248
  if (NULL != pAgg) {
×
UNCOV
4249
    return pAgg->numOfNull > 0 ? true : false;
×
4250
  }
4251

UNCOV
4252
  if (!pData->hasNull) {
×
UNCOV
4253
    return false;
×
4254
  }
4255

4256
  int64_t endIdx = startIdx + rows;
×
UNCOV
4257
  for (int64_t i = startIdx; i < endIdx; ++i) {
×
UNCOV
4258
    if (colDataIsNull_s(pData, i)) {
×
UNCOV
4259
      return true;
×
4260
    }
4261
  }
4262

UNCOV
4263
  return false;
×
4264
}
4265

4266

4267
/*
4268
 * +------------------------------------+--------------+--------------+
4269
 * |            null bitmap             |              |              |
4270
 * |(n columns, one bit for each column)| src column #1| src column #2|
4271
 * +------------------------------------+--------------+--------------+
4272
 */
4273
int32_t serializeTupleData(SqlFunctionCtx* pCtx, const SSDataBlock* pSrcBlock, int32_t rowIndex, SSubsidiaryResInfo* pSubsidiaryies,
139,976,304✔
4274
                           char* buf, char** res) {
4275
  char* nullList = buf;
139,976,304✔
4276
  char* pStart = (char*)(nullList + sizeof(bool) * pSubsidiaryies->num);
139,976,304✔
4277

4278
  int32_t offset = 0;
139,978,365✔
4279
  for (int32_t i = 0; i < pSubsidiaryies->num; ++i) {
443,703,507✔
4280
    SqlFunctionCtx* pc = pSubsidiaryies->pCtx[i];
303,727,654✔
4281

4282
    // group_key function has its own process function
4283
    // do not process there
4284
    if (fmIsGroupKeyFunc(pc->functionId)) {
303,726,908✔
UNCOV
4285
      continue;
×
4286
    }
4287

4288
    if (fmIsSelectValueFunc(pc->functionId)) {
303,720,100✔
4289
      SFunctParam* pFuncParam = &pc->pExpr->base.pParam[0];
303,720,968✔
4290
      int32_t      srcSlotId = pFuncParam->pCol->slotId;
303,722,853✔
4291

4292
      SColumnInfoData* pCol = taosArrayGet(pSrcBlock->pDataBlock, srcSlotId);
303,726,870✔
4293
      if (NULL == pCol) {
303,721,616✔
UNCOV
4294
        return TSDB_CODE_OUT_OF_RANGE;
×
4295
      }
4296
      if ((nullList[i] = colDataIsNull_s(pCol, rowIndex)) == true) {
607,447,058✔
4297
        offset += pCol->info.bytes;
91,884,173✔
4298
        continue;
91,884,173✔
4299
      }
4300

4301
      char* p = colDataGetData(pCol, rowIndex);
211,842,402✔
4302
      if (IS_VAR_DATA_TYPE(pCol->info.type)) {
211,841,921✔
4303
        int32_t bytes = calcStrBytesByType(pCol->info.type, p);
8,355,980✔
4304
        (void)memcpy(pStart + offset, p, bytes);
8,341,045✔
4305
      } else {
4306
        (void)memcpy(pStart + offset, p, pCol->info.bytes);
203,498,938✔
4307
      }
4308

4309
      offset += pCol->info.bytes;
211,838,913✔
4310
      continue;
211,838,254✔
4311
    }
4312
  }
4313

4314
  *res = buf;
139,971,506✔
4315
  return TSDB_CODE_SUCCESS;
139,977,695✔
4316
}
4317

4318
static int32_t doSaveTupleData(SSerializeDataHandle* pHandle, const void* pBuf, size_t length, SWinKey* key,
2,147,483,647✔
4319
                               STuplePos* pPos, SFunctionStateStore* pStore) {
4320
  STuplePos p = {0};
2,147,483,647✔
4321
  if (pHandle->pBuf != NULL) {
2,147,483,647✔
4322
    SFilePage* pPage = NULL;
2,147,483,647✔
4323

4324
    if (pHandle->currentPage == -1) {
2,147,483,647✔
4325
      pPage = getNewBufPage(pHandle->pBuf, &pHandle->currentPage);
5,870,710✔
4326
      if (pPage == NULL) {
5,877,032✔
UNCOV
4327
        return terrno;
×
4328
      }
4329
      pPage->num = sizeof(SFilePage);
5,877,032✔
4330
    } else {
4331
      pPage = getBufPage(pHandle->pBuf, pHandle->currentPage);
2,147,483,647✔
4332
      if (pPage == NULL) {
2,147,483,647✔
4333
        return terrno;
×
4334
      }
4335
      if (pPage->num + length > getBufPageSize(pHandle->pBuf)) {
2,147,483,647✔
4336
        // current page is all used, let's prepare a new buffer page
4337
        releaseBufPage(pHandle->pBuf, pPage);
5,268,343✔
4338
        pPage = getNewBufPage(pHandle->pBuf, &pHandle->currentPage);
5,268,343✔
4339
        if (pPage == NULL) {
5,268,343✔
4340
          return terrno;
×
4341
        }
4342
        pPage->num = sizeof(SFilePage);
5,268,343✔
4343
      }
4344
    }
4345

4346
    p = (STuplePos){.pageId = pHandle->currentPage, .offset = pPage->num};
2,147,483,647✔
4347
    (void)memcpy(pPage->data + pPage->num, pBuf, length);
2,147,483,647✔
4348

4349
    pPage->num += length;
2,147,483,647✔
4350
    setBufPageDirty(pPage, true);
2,147,483,647✔
4351
    releaseBufPage(pHandle->pBuf, pPage);
2,147,483,647✔
4352
  } else {  // other tuple save policy
4353
    if (pStore->streamStateFuncPut(pHandle->pState, key, pBuf, length) >= 0) {
1,695✔
UNCOV
4354
      p.streamTupleKey = *key;
×
4355
    }
4356
  }
4357

4358
  *pPos = p;
2,147,483,647✔
4359
  return TSDB_CODE_SUCCESS;
2,147,483,647✔
4360
}
4361

4362
int32_t saveTupleData(SqlFunctionCtx* pCtx, int32_t rowIndex, const SSDataBlock* pSrcBlock, STuplePos* pPos) {
103,289,893✔
4363
  int32_t code = prepareBuf(pCtx);
103,289,893✔
4364
  if (TSDB_CODE_SUCCESS != code) {
103,289,893✔
UNCOV
4365
    return code;
×
4366
  }
4367

4368
  SWinKey key = {0};
103,289,893✔
4369
  if (pCtx->saveHandle.pBuf == NULL) {
103,290,895✔
4370
    SColumnInfoData* pColInfo = taosArrayGet(pSrcBlock->pDataBlock, pCtx->saveHandle.pState->tsIndex);
×
4371
    if (NULL == pColInfo) {
×
UNCOV
4372
      return TSDB_CODE_OUT_OF_RANGE;
×
4373
    }
UNCOV
4374
    if (pColInfo->info.type != TSDB_DATA_TYPE_TIMESTAMP) {
×
UNCOV
4375
      return TSDB_CODE_FUNC_FUNTION_PARA_TYPE;
×
4376
    }
UNCOV
4377
    key.groupId = pSrcBlock->info.id.groupId;
×
UNCOV
4378
    key.ts = *(int64_t*)colDataGetData(pColInfo, rowIndex);
×
UNCOV
4379
    key.numInGroup = pCtx->pExpr->pExpr->_function.bindExprID;
×
4380
  }
4381

4382
  char* buf = NULL;
103,288,748✔
4383
  code = serializeTupleData(pCtx, pSrcBlock, rowIndex, &pCtx->subsidiaries, pCtx->subsidiaries.buf, &buf);
103,289,493✔
4384
  if (TSDB_CODE_SUCCESS != code) {
103,287,805✔
UNCOV
4385
    return code;
×
4386
  }
4387
  return doSaveTupleData(&pCtx->saveHandle, buf, pCtx->subsidiaries.rowLen, &key, pPos, pCtx->pStore);
103,287,805✔
4388
}
4389

4390
static int32_t doUpdateTupleData(SSerializeDataHandle* pHandle, const void* pBuf, size_t length, STuplePos* pPos,
36,688,617✔
4391
                                 SFunctionStateStore* pStore) {
4392
  if (pHandle->pBuf != NULL) {
36,688,617✔
4393
    SFilePage* pPage = getBufPage(pHandle->pBuf, pPos->pageId);
36,688,617✔
4394
    if (pPage == NULL) {
36,688,908✔
UNCOV
4395
      return terrno;
×
4396
    }
4397
    (void)memcpy(pPage->data + pPos->offset, pBuf, length);
36,688,908✔
4398
    setBufPageDirty(pPage, true);
36,688,908✔
4399
    releaseBufPage(pHandle->pBuf, pPage);
36,689,417✔
4400
  } else {
UNCOV
4401
    int32_t code = pStore->streamStateFuncPut(pHandle->pState, &pPos->streamTupleKey, pBuf, length);
×
UNCOV
4402
    if (TSDB_CODE_SUCCESS != code) {
×
UNCOV
4403
      return code;
×
4404
    }
4405
  }
4406

4407
  return TSDB_CODE_SUCCESS;
36,689,417✔
4408
}
4409

4410
int32_t updateTupleData(SqlFunctionCtx* pCtx, int32_t rowIndex, const SSDataBlock* pSrcBlock, STuplePos* pPos) {
36,689,017✔
4411
  int32_t code = prepareBuf(pCtx);
36,689,017✔
4412
  if (TSDB_CODE_SUCCESS != code) {
36,689,817✔
UNCOV
4413
    return code;
×
4414
  }
4415

4416
  char* buf = NULL;
36,689,817✔
4417
  code = serializeTupleData(pCtx, pSrcBlock, rowIndex, &pCtx->subsidiaries, pCtx->subsidiaries.buf, &buf);
36,689,817✔
4418
  if (TSDB_CODE_SUCCESS != code) {
36,688,617✔
UNCOV
4419
    return code;
×
4420
  }
4421
  return doUpdateTupleData(&pCtx->saveHandle, buf, pCtx->subsidiaries.rowLen, pPos, pCtx->pStore);
36,688,617✔
4422
}
4423

4424
static int32_t doLoadTupleData(SSerializeDataHandle* pHandle, const STuplePos* pPos, SFunctionStateStore* pStore,
103,204,343✔
4425
                               char** value) {
4426
  if (pHandle->pBuf != NULL) {
103,204,343✔
4427
    SFilePage* pPage = getBufPage(pHandle->pBuf, pPos->pageId);
103,204,343✔
4428
    if (pPage == NULL) {
103,204,343✔
4429
      *value = NULL;
×
UNCOV
4430
      return terrno;
×
4431
    }
4432
    *value = pPage->data + pPos->offset;
103,204,343✔
4433
    releaseBufPage(pHandle->pBuf, pPage);
103,204,343✔
4434
    return TSDB_CODE_SUCCESS;
103,204,945✔
4435
  } else {
UNCOV
4436
    *value = NULL;
×
UNCOV
4437
    int32_t vLen;
×
UNCOV
4438
    int32_t code = pStore->streamStateFuncGet(pHandle->pState, &pPos->streamTupleKey, (void**)(value), &vLen);
×
UNCOV
4439
    if (TSDB_CODE_SUCCESS != code) {
×
UNCOV
4440
      return code;
×
4441
    }
UNCOV
4442
    return TSDB_CODE_SUCCESS;
×
4443
  }
4444
}
4445

4446
int32_t loadTupleData(SqlFunctionCtx* pCtx, const STuplePos* pPos, char** value) {
103,204,343✔
4447
  return doLoadTupleData(&pCtx->saveHandle, pPos, pCtx->pStore, value);
103,204,343✔
4448
}
4449

4450
int32_t topBotFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
7,775,859✔
4451
  int32_t code = TSDB_CODE_SUCCESS;
7,775,859✔
4452

4453
  SResultRowEntryInfo* pEntryInfo = GET_RES_INFO(pCtx);
7,775,859✔
4454
  STopBotRes*          pRes = getTopBotOutputInfo(pCtx);
7,775,859✔
4455

4456
  int16_t type = pCtx->pExpr->base.resSchema.type;
7,775,859✔
4457
  int32_t slotId = pCtx->pExpr->base.resSchema.slotId;
7,775,859✔
4458

4459
  SColumnInfoData* pCol = taosArrayGet(pBlock->pDataBlock, slotId);
7,775,859✔
4460
  if (NULL == pCol) {
7,775,859✔
4461
    return TSDB_CODE_OUT_OF_RANGE;
×
4462
  }
4463

4464
  // todo assign the tag value and the corresponding row data
4465
  int32_t currentRow = pBlock->info.rows;
7,775,859✔
4466
  if (pEntryInfo->numOfRes <= 0) {
7,775,859✔
4467
    colDataSetNULL(pCol, currentRow);
55,142✔
4468
    code = setSelectivityValue(pCtx, pBlock, &pRes->nullTuplePos, currentRow);
55,142✔
4469
    return code;
55,142✔
4470
  }
4471
  for (int32_t i = 0; i < pEntryInfo->numOfRes; ++i) {
52,869,518✔
4472
    STopBotResItem* pItem = &pRes->pItems[i];
45,148,801✔
4473
    code = colDataSetVal(pCol, currentRow, (const char*)&pItem->v.i, false);
45,148,801✔
4474
    if (TSDB_CODE_SUCCESS != code) {
45,148,801✔
4475
      return code;
×
4476
    }
4477
#ifdef BUF_PAGE_DEBUG
4478
    qDebug("page_finalize i:%d,item:%p,pageId:%d, offset:%d\n", i, pItem, pItem->tuplePos.pageId,
4479
           pItem->tuplePos.offset);
4480
#endif
4481
    code = setSelectivityValue(pCtx, pBlock, &pRes->pItems[i].tuplePos, currentRow);
45,148,801✔
4482
    if (TSDB_CODE_SUCCESS != code) {
45,148,801✔
4483
      return code;
×
4484
    }
4485
    currentRow += 1;
45,148,801✔
4486
  }
4487

4488
  return code;
7,720,717✔
4489
}
4490

UNCOV
4491
int32_t addResult(SqlFunctionCtx* pCtx, STopBotResItem* pSourceItem, int16_t type, bool isTopQuery) {
×
UNCOV
4492
  SResultRowEntryInfo* pEntryInfo = GET_RES_INFO(pCtx);
×
4493
  STopBotRes*          pRes = getTopBotOutputInfo(pCtx);
×
4494
  STopBotResItem*      pItems = pRes->pItems;
×
4495
  int32_t              code = TSDB_CODE_SUCCESS;
×
4496

4497
  // not full yet
UNCOV
4498
  if (pEntryInfo->numOfRes < pRes->maxSize) {
×
UNCOV
4499
    STopBotResItem* pItem = &pItems[pEntryInfo->numOfRes];
×
UNCOV
4500
    pItem->v = pSourceItem->v;
×
4501
    pItem->uid = pSourceItem->uid;
×
UNCOV
4502
    pItem->tuplePos.pageId = -1;
×
UNCOV
4503
    replaceTupleData(&pItem->tuplePos, &pSourceItem->tuplePos);
×
4504
    pEntryInfo->numOfRes++;
×
4505
    code = taosheapsort((void*)pItems, sizeof(STopBotResItem), pEntryInfo->numOfRes, (const void*)&type,
×
4506
                        topBotResComparFn, !isTopQuery);
×
4507
    if (TSDB_CODE_SUCCESS != code) {
×
4508
      return code;
×
4509
    }
4510
  } else {  // replace the minimum value in the result
4511
    if ((isTopQuery && ((IS_SIGNED_NUMERIC_TYPE(type) && pSourceItem->v.i > pItems[0].v.i) ||
×
4512
                        (IS_UNSIGNED_NUMERIC_TYPE(type) && pSourceItem->v.u > pItems[0].v.u) ||
×
UNCOV
4513
                        (TSDB_DATA_TYPE_FLOAT == type && pSourceItem->v.f > pItems[0].v.f) ||
×
UNCOV
4514
                        (TSDB_DATA_TYPE_DOUBLE == type && pSourceItem->v.d > pItems[0].v.d))) ||
×
4515
        (!isTopQuery && ((IS_SIGNED_NUMERIC_TYPE(type) && pSourceItem->v.i < pItems[0].v.i) ||
×
UNCOV
4516
                         (IS_UNSIGNED_NUMERIC_TYPE(type) && pSourceItem->v.u < pItems[0].v.u) ||
×
UNCOV
4517
                         (TSDB_DATA_TYPE_FLOAT == type && pSourceItem->v.f < pItems[0].v.f) ||
×
4518
                         (TSDB_DATA_TYPE_DOUBLE == type && pSourceItem->v.d < pItems[0].v.d)))) {
×
4519
      // replace the old data and the coresponding tuple data
4520
      STopBotResItem* pItem = &pItems[0];
×
4521
      pItem->v = pSourceItem->v;
×
4522
      pItem->uid = pSourceItem->uid;
×
4523

4524
      // save the data of this tuple by over writing the old data
4525
      replaceTupleData(&pItem->tuplePos, &pSourceItem->tuplePos);
×
4526
      code = taosheapadjust((void*)pItems, sizeof(STopBotResItem), 0, pEntryInfo->numOfRes - 1, (const void*)&type,
×
UNCOV
4527
                            topBotResComparFn, NULL, !isTopQuery);
×
UNCOV
4528
      if (TSDB_CODE_SUCCESS != code) {
×
4529
        return code;
×
4530
      }
4531
    }
4532
  }
UNCOV
4533
  return code;
×
4534
}
4535

UNCOV
4536
int32_t topCombine(SqlFunctionCtx* pDestCtx, SqlFunctionCtx* pSourceCtx) {
×
UNCOV
4537
  SResultRowEntryInfo* pSResInfo = GET_RES_INFO(pSourceCtx);
×
UNCOV
4538
  STopBotRes*          pSBuf = getTopBotOutputInfo(pSourceCtx);
×
UNCOV
4539
  int16_t              type = pSBuf->type;
×
UNCOV
4540
  int32_t              code = TSDB_CODE_SUCCESS;
×
4541
  for (int32_t i = 0; i < pSResInfo->numOfRes; i++) {
×
UNCOV
4542
    code = addResult(pDestCtx, pSBuf->pItems + i, type, true);
×
UNCOV
4543
    if (TSDB_CODE_SUCCESS != code) {
×
4544
      return code;
×
4545
    }
4546
  }
UNCOV
4547
  return TSDB_CODE_SUCCESS;
×
4548
}
4549

UNCOV
4550
int32_t bottomCombine(SqlFunctionCtx* pDestCtx, SqlFunctionCtx* pSourceCtx) {
×
UNCOV
4551
  SResultRowEntryInfo* pSResInfo = GET_RES_INFO(pSourceCtx);
×
UNCOV
4552
  STopBotRes*          pSBuf = getTopBotOutputInfo(pSourceCtx);
×
UNCOV
4553
  int16_t              type = pSBuf->type;
×
UNCOV
4554
  int32_t              code = TSDB_CODE_SUCCESS;
×
UNCOV
4555
  for (int32_t i = 0; i < pSResInfo->numOfRes; i++) {
×
UNCOV
4556
    code = addResult(pDestCtx, pSBuf->pItems + i, type, false);
×
UNCOV
4557
    if (TSDB_CODE_SUCCESS != code) {
×
UNCOV
4558
      return code;
×
4559
    }
4560
  }
UNCOV
4561
  return TSDB_CODE_SUCCESS;
×
4562
}
4563

4564
int32_t getSpreadInfoSize() { return (int32_t)sizeof(SSpreadInfo); }
8,420,358✔
4565

4566
bool getSpreadFuncEnv(SFunctionNode* UNUSED_PARAM(pFunc), SFuncExecEnv* pEnv) {
4,098,836✔
4567
  pEnv->calcMemSize = sizeof(SSpreadInfo);
4,098,836✔
4568
  return true;
4,099,350✔
4569
}
4570

4571
int32_t spreadFunctionSetup(SqlFunctionCtx* pCtx, SResultRowEntryInfo* pResultInfo) {
90,233,051✔
4572
  if (pResultInfo->initialized) {
90,233,051✔
UNCOV
4573
    return TSDB_CODE_SUCCESS;
×
4574
  }
4575
  if (TSDB_CODE_SUCCESS != functionSetup(pCtx, pResultInfo)) {
90,239,259✔
UNCOV
4576
    return TSDB_CODE_FUNC_SETUP_ERROR;
×
4577
  }
4578

4579
  SSpreadInfo* pInfo = GET_ROWCELL_INTERBUF(pResultInfo);
90,241,656✔
4580
  SET_DOUBLE_VAL(&pInfo->min, DBL_MAX);
90,241,656✔
4581
  SET_DOUBLE_VAL(&pInfo->max, -DBL_MAX);
90,240,110✔
4582
  pInfo->hasResult = false;
90,242,627✔
4583
  return TSDB_CODE_SUCCESS;
90,241,182✔
4584
}
4585

4586
int32_t spreadFunction(SqlFunctionCtx* pCtx) {
140,529,638✔
4587
  int32_t numOfElems = 0;
140,529,638✔
4588

4589
  // Only the pre-computing information loaded and actual data does not loaded
4590
  SInputColumnInfoData* pInput = &pCtx->input;
140,529,638✔
4591
  SColumnDataAgg*       pAgg = pInput->pColumnDataAgg[0];
140,541,520✔
4592
  int32_t               type = pInput->pData[0]->info.type;
140,571,293✔
4593

4594
  SSpreadInfo* pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
140,585,267✔
4595

4596
  if (pInput->colDataSMAIsSet) {
140,592,660✔
4597
    numOfElems = pInput->numOfRows - pAgg->numOfNull;
43,644,760✔
4598
    if (numOfElems == 0) {
43,651,800✔
4599
      goto _spread_over;
30,967,970✔
4600
    }
4601
    double tmin = 0.0, tmax = 0.0;
12,683,830✔
4602
    if (IS_SIGNED_NUMERIC_TYPE(type) || IS_TIMESTAMP_TYPE(type)) {
12,683,830✔
4603
      tmin = (double)GET_INT64_VAL(&pAgg->min);
6,489,415✔
4604
      tmax = (double)GET_INT64_VAL(&pAgg->max);
6,489,415✔
4605
    } else if (IS_FLOAT_TYPE(type)) {
6,194,415✔
UNCOV
4606
      tmin = GET_DOUBLE_VAL(&pAgg->min);
×
UNCOV
4607
      tmax = GET_DOUBLE_VAL(&pAgg->max);
×
4608
    } else if (IS_UNSIGNED_NUMERIC_TYPE(type)) {
6,194,415✔
4609
      tmin = (double)GET_UINT64_VAL(&pAgg->min);
6,192,660✔
4610
      tmax = (double)GET_UINT64_VAL(&pAgg->max);
6,192,660✔
4611
    }
4612

4613
    if (GET_DOUBLE_VAL(&pInfo->min) > tmin) {
12,685,585✔
4614
      SET_DOUBLE_VAL(&pInfo->min, tmin);
578,315✔
4615
    }
4616

4617
    if (GET_DOUBLE_VAL(&pInfo->max) < tmax) {
12,684,415✔
4618
      SET_DOUBLE_VAL(&pInfo->max, tmax);
618,920✔
4619
    }
4620

4621
  } else {  // computing based on the true data block
4622
    SColumnInfoData* pCol = pInput->pData[0];
96,929,161✔
4623

4624
    int32_t start = pInput->startRowIndex;
96,933,813✔
4625
    // check the valid data one by one
4626
    for (int32_t i = start; i < pInput->numOfRows + start; ++i) {
2,147,483,647✔
4627
      if (colDataIsNull_f(pCol, i)) {
2,147,483,647✔
4628
        continue;
2,147,483,647✔
4629
      }
4630

4631
      char* data = colDataGetData(pCol, i);
2,147,483,647✔
4632

4633
      double v = 0;
2,147,483,647✔
4634
      GET_TYPED_DATA(v, double, type, data, typeGetTypeModFromColInfo(&pCol->info));
2,147,483,647✔
4635
      if (v < GET_DOUBLE_VAL(&pInfo->min)) {
2,147,483,647✔
4636
        SET_DOUBLE_VAL(&pInfo->min, v);
91,967,045✔
4637
      }
4638

4639
      if (v > GET_DOUBLE_VAL(&pInfo->max)) {
2,147,483,647✔
4640
        SET_DOUBLE_VAL(&pInfo->max, v);
95,105,128✔
4641
      }
4642

4643
      numOfElems += 1;
2,147,483,647✔
4644
    }
4645
  }
4646

4647
_spread_over:
96,931,693✔
4648
  // data in the check operation are all null, not output
4649
  SET_VAL(GET_RES_INFO(pCtx), numOfElems, 1);
140,582,908✔
4650
  if (numOfElems > 0) {
140,577,782✔
4651
    pInfo->hasResult = true;
95,978,745✔
4652
  }
4653

4654
  return TSDB_CODE_SUCCESS;
140,571,634✔
4655
}
4656

4657
static void spreadTransferInfo(SSpreadInfo* pInput, SSpreadInfo* pOutput) {
7,451,994✔
4658
  pOutput->hasResult = pInput->hasResult;
7,451,994✔
4659
  if (pInput->max > pOutput->max) {
7,451,994✔
4660
    pOutput->max = pInput->max;
5,253,279✔
4661
  }
4662

4663
  if (pInput->min < pOutput->min) {
7,451,994✔
4664
    pOutput->min = pInput->min;
5,247,869✔
4665
  }
4666
}
7,451,994✔
4667

4668
int32_t spreadFunctionMerge(SqlFunctionCtx* pCtx) {
5,978,939✔
4669
  SInputColumnInfoData* pInput = &pCtx->input;
5,978,939✔
4670
  SColumnInfoData*      pCol = pInput->pData[0];
5,978,939✔
4671

4672
  if (IS_NULL_TYPE(pCol->info.type)) {
5,978,939✔
UNCOV
4673
    SET_VAL(GET_RES_INFO(pCtx), 0, 1);
×
UNCOV
4674
    return TSDB_CODE_SUCCESS;
×
4675
  }
4676

4677
  if (pCol->info.type != TSDB_DATA_TYPE_BINARY) {
5,978,939✔
UNCOV
4678
    return TSDB_CODE_FUNC_FUNTION_PARA_TYPE;
×
4679
  }
4680

4681
  SSpreadInfo* pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
5,978,939✔
4682

4683
  int32_t start = pInput->startRowIndex;
5,978,939✔
4684
  for (int32_t i = start; i < start + pInput->numOfRows; ++i) {
14,048,119✔
4685
    if (colDataIsNull_s(pCol, i)) continue;
16,138,360✔
4686
    char*        data = colDataGetData(pCol, i);
8,069,180✔
4687
    SSpreadInfo* pInputInfo = (SSpreadInfo*)varDataVal(data);
8,069,180✔
4688
    if (pInputInfo->hasResult) {
8,069,180✔
4689
      spreadTransferInfo(pInputInfo, pInfo);
7,451,994✔
4690
    }
4691
  }
4692

4693
  if (pInfo->hasResult) {
5,978,939✔
4694
    GET_RES_INFO(pCtx)->numOfRes = 1;
5,632,717✔
4695
  }
4696

4697
  return TSDB_CODE_SUCCESS;
5,978,939✔
4698
}
4699

4700
int32_t spreadFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
74,997,576✔
4701
  SSpreadInfo* pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
74,997,576✔
4702
  if (pInfo->hasResult == true) {
74,998,090✔
4703
    SET_DOUBLE_VAL(&pInfo->result, pInfo->max - pInfo->min);
64,468,605✔
4704
  } else {
4705
    GET_RES_INFO(pCtx)->isNullRes = 1;
10,528,971✔
4706
  }
4707
  return functionFinalize(pCtx, pBlock);
74,997,576✔
4708
}
4709

4710
int32_t spreadPartialFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
8,082,344✔
4711
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
8,082,344✔
4712
  SSpreadInfo*         pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
8,082,344✔
4713
  int32_t              resultBytes = getSpreadInfoSize();
8,082,344✔
4714
  char*                res = taosMemoryCalloc(resultBytes + VARSTR_HEADER_SIZE, sizeof(char));
8,082,344✔
4715

4716
  if (NULL == res) {
8,082,344✔
4717
    return terrno;
×
4718
  }
4719
  (void)memcpy(varDataVal(res), pInfo, resultBytes);
8,082,344✔
4720
  varDataSetLen(res, resultBytes);
8,082,344✔
4721

4722
  int32_t          slotId = pCtx->pExpr->base.resSchema.slotId;
8,082,344✔
4723
  int32_t          code = TSDB_CODE_SUCCESS;
8,082,344✔
4724
  SColumnInfoData* pCol = taosArrayGet(pBlock->pDataBlock, slotId);
8,082,344✔
4725
  if (NULL == pCol) {
8,082,344✔
UNCOV
4726
    code = terrno;
×
UNCOV
4727
    goto _exit;
×
4728
  }
4729

4730
  code = colDataSetVal(pCol, pBlock->info.rows, res, false);
8,082,344✔
4731
  if (TSDB_CODE_SUCCESS != code) {
8,082,344✔
4732
    goto _exit;
×
4733
  }
4734

4735
_exit:
8,082,344✔
4736
  taosMemoryFree(res);
8,082,344✔
4737
  return code;
8,082,344✔
4738
}
4739

UNCOV
4740
int32_t spreadCombine(SqlFunctionCtx* pDestCtx, SqlFunctionCtx* pSourceCtx) {
×
UNCOV
4741
  SResultRowEntryInfo* pDResInfo = GET_RES_INFO(pDestCtx);
×
UNCOV
4742
  SSpreadInfo*         pDBuf = GET_ROWCELL_INTERBUF(pDResInfo);
×
4743

UNCOV
4744
  SResultRowEntryInfo* pSResInfo = GET_RES_INFO(pSourceCtx);
×
UNCOV
4745
  SSpreadInfo*         pSBuf = GET_ROWCELL_INTERBUF(pSResInfo);
×
UNCOV
4746
  spreadTransferInfo(pSBuf, pDBuf);
×
UNCOV
4747
  pDResInfo->numOfRes = TMAX(pDResInfo->numOfRes, pSResInfo->numOfRes);
×
UNCOV
4748
  pDResInfo->isNullRes &= pSResInfo->isNullRes;
×
UNCOV
4749
  return TSDB_CODE_SUCCESS;
×
4750
}
4751

UNCOV
4752
int32_t getElapsedInfoSize() { return (int32_t)sizeof(SElapsedInfo); }
×
4753

4754
bool getElapsedFuncEnv(SFunctionNode* UNUSED_PARAM(pFunc), SFuncExecEnv* pEnv) {
2,132,542✔
4755
  pEnv->calcMemSize = sizeof(SElapsedInfo);
2,132,542✔
4756
  return true;
2,132,542✔
4757
}
4758

4759
int32_t elapsedFunctionSetup(SqlFunctionCtx* pCtx, SResultRowEntryInfo* pResultInfo) {
4,270,622✔
4760
  if (pResultInfo->initialized) {
4,270,622✔
4761
    return TSDB_CODE_SUCCESS;
×
4762
  }
4763
  if (TSDB_CODE_SUCCESS != functionSetup(pCtx, pResultInfo)) {
4,270,622✔
4764
    return TSDB_CODE_FUNC_SETUP_ERROR;
×
4765
  }
4766

4767
  SElapsedInfo* pInfo = GET_ROWCELL_INTERBUF(pResultInfo);
4,270,187✔
4768
  pInfo->result = 0;
4,270,622✔
4769
  pInfo->min = TSKEY_MAX;
4,270,622✔
4770
  pInfo->max = 0;
4,270,187✔
4771

4772
  if (pCtx->numOfParams > 1) {
4,269,752✔
4773
    pInfo->timeUnit = pCtx->param[1].param.i;
2,415,516✔
4774
  } else {
4775
    pInfo->timeUnit = 1;
1,855,106✔
4776
  }
4777

4778
  return TSDB_CODE_SUCCESS;
4,270,622✔
4779
}
4780

4781
int32_t elapsedFunction(SqlFunctionCtx* pCtx) {
4,939,648✔
4782
  int32_t numOfElems = 0;
4,939,648✔
4783

4784
  // Only the pre-computing information loaded and actual data does not loaded
4785
  SInputColumnInfoData* pInput = &pCtx->input;
4,939,648✔
4786
  SColumnDataAgg*       pAgg = pInput->pColumnDataAgg[0];
4,939,648✔
4787

4788
  SElapsedInfo* pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
4,938,778✔
4789

4790
  numOfElems = pInput->numOfRows;  // since this is the primary timestamp, no need to exclude NULL values
4,938,185✔
4791
  if (numOfElems == 0) {
4,937,394✔
4792
    // for stream
UNCOV
4793
    if (pCtx->end.key != INT64_MIN) {
×
UNCOV
4794
      pInfo->max = pCtx->end.key + 1;
×
4795
    }
UNCOV
4796
    goto _elapsed_over;
×
4797
  }
4798

4799
  if (pInput->colDataSMAIsSet) {
4,937,394✔
4800
    if (pInfo->min == TSKEY_MAX) {
×
UNCOV
4801
      pInfo->min = GET_INT64_VAL(&pAgg->min);
×
UNCOV
4802
      pInfo->max = GET_INT64_VAL(&pAgg->max);
×
4803
    } else {
UNCOV
4804
      if (pCtx->order == TSDB_ORDER_ASC) {
×
UNCOV
4805
        pInfo->max = GET_INT64_VAL(&pAgg->max);
×
4806
      } else {
4807
        pInfo->min = GET_INT64_VAL(&pAgg->min);
×
4808
      }
4809
    }
4810
  } else {  // computing based on the true data block
4811
    if (0 == pInput->numOfRows) {
4,938,343✔
UNCOV
4812
      if (pCtx->order == TSDB_ORDER_DESC) {
×
4813
        if (pCtx->end.key != INT64_MIN) {
×
UNCOV
4814
          pInfo->min = pCtx->end.key;
×
4815
        }
4816
      } else {
UNCOV
4817
        if (pCtx->end.key != INT64_MIN) {
×
UNCOV
4818
          pInfo->max = pCtx->end.key + 1;
×
4819
        }
4820
      }
UNCOV
4821
      goto _elapsed_over;
×
4822
    }
4823

4824
    SColumnInfoData* pCol = pInput->pData[0];
4,938,185✔
4825

4826
    int32_t start = pInput->startRowIndex;
4,938,620✔
4827
    TSKEY*  ptsList = (int64_t*)colDataGetData(pCol, 0);
4,937,829✔
4828
    if (pCtx->order == TSDB_ORDER_DESC) {
4,940,162✔
4829
      if (pCtx->start.key == INT64_MIN) {
32,410✔
4830
        pInfo->max = (pInfo->max < ptsList[start]) ? ptsList[start] : pInfo->max;
32,410✔
4831
      } else {
4832
        pInfo->max = pCtx->start.key + 1;
×
4833
      }
4834

4835
      if (pCtx->end.key == INT64_MIN) {
32,410✔
4836
        pInfo->min =
32,410✔
4837
            (pInfo->min > ptsList[start + pInput->numOfRows - 1]) ? ptsList[start + pInput->numOfRows - 1] : pInfo->min;
32,410✔
4838
      } else {
4839
        pInfo->min = pCtx->end.key;
×
4840
      }
4841
    } else {
4842
      if (pCtx->start.key == INT64_MIN) {
4,907,317✔
4843
        pInfo->min = (pInfo->min > ptsList[start]) ? ptsList[start] : pInfo->min;
4,907,752✔
4844
      } else {
4845
        pInfo->min = pCtx->start.key;
×
4846
      }
4847

4848
      if (pCtx->end.key == INT64_MIN) {
4,906,447✔
4849
        pInfo->max =
4,849,094✔
4850
            (pInfo->max < ptsList[start + pInput->numOfRows - 1]) ? ptsList[start + pInput->numOfRows - 1] : pInfo->max;
4,849,608✔
4851
      } else {
4852
        pInfo->max = pCtx->end.key + 1;
57,195✔
4853
      }
4854
    }
4855
  }
4856

4857
_elapsed_over:
4,939,727✔
4858
  // data in the check operation are all null, not output
4859
  SET_VAL(GET_RES_INFO(pCtx), numOfElems, 1);
4,939,727✔
4860

4861
  return TSDB_CODE_SUCCESS;
4,939,727✔
4862
}
4863

UNCOV
4864
static void elapsedTransferInfo(SElapsedInfo* pInput, SElapsedInfo* pOutput) {
×
UNCOV
4865
  pOutput->timeUnit = pInput->timeUnit;
×
UNCOV
4866
  if (pOutput->min > pInput->min) {
×
UNCOV
4867
    pOutput->min = pInput->min;
×
4868
  }
4869

UNCOV
4870
  if (pOutput->max < pInput->max) {
×
4871
    pOutput->max = pInput->max;
×
4872
  }
4873
}
×
4874

4875
int32_t elapsedFunctionMerge(SqlFunctionCtx* pCtx) {
×
UNCOV
4876
  SInputColumnInfoData* pInput = &pCtx->input;
×
4877
  SColumnInfoData*      pCol = pInput->pData[0];
×
4878
  if (pCol->info.type != TSDB_DATA_TYPE_BINARY) {
×
UNCOV
4879
    return TSDB_CODE_FUNC_FUNTION_PARA_TYPE;
×
4880
  }
4881

UNCOV
4882
  SElapsedInfo* pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
×
4883

4884
  int32_t start = pInput->startRowIndex;
×
4885

4886
  for (int32_t i = start; i < start + pInput->numOfRows; ++i) {
×
4887
    char*         data = colDataGetData(pCol, i);
×
4888
    SElapsedInfo* pInputInfo = (SElapsedInfo*)varDataVal(data);
×
UNCOV
4889
    elapsedTransferInfo(pInputInfo, pInfo);
×
4890
  }
4891

4892
  SET_VAL(GET_RES_INFO(pCtx), 1, 1);
×
4893
  return TSDB_CODE_SUCCESS;
×
4894
}
4895

4896
int32_t elapsedFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
4,271,057✔
4897
  SElapsedInfo* pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
4,271,057✔
4898
  double        result = (double)(pInfo->max - pInfo->min);
4,271,057✔
4899
  pInfo->result = fabs(result) / pInfo->timeUnit;
4,271,057✔
4900
  return functionFinalize(pCtx, pBlock);
4,271,057✔
4901
}
4902

UNCOV
4903
int32_t elapsedPartialFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
×
4904
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
×
4905
  SElapsedInfo*        pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
×
UNCOV
4906
  int32_t              resultBytes = getElapsedInfoSize();
×
4907
  char*                res = taosMemoryCalloc(resultBytes + VARSTR_HEADER_SIZE, sizeof(char));
×
4908

4909
  if (NULL == res) {
×
4910
    return terrno;
×
4911
  }
UNCOV
4912
  (void)memcpy(varDataVal(res), pInfo, resultBytes);
×
UNCOV
4913
  varDataSetLen(res, resultBytes);
×
4914

UNCOV
4915
  int32_t          slotId = pCtx->pExpr->base.resSchema.slotId;
×
UNCOV
4916
  int32_t          code = TSDB_CODE_SUCCESS;
×
UNCOV
4917
  SColumnInfoData* pCol = taosArrayGet(pBlock->pDataBlock, slotId);
×
UNCOV
4918
  if (NULL == pCol) {
×
UNCOV
4919
    code = terrno;
×
UNCOV
4920
    goto _exit;
×
4921
  }
4922

UNCOV
4923
  code = colDataSetVal(pCol, pBlock->info.rows, res, false);
×
UNCOV
4924
  if (TSDB_CODE_SUCCESS != code) {
×
UNCOV
4925
    goto _exit;
×
4926
  }
UNCOV
4927
_exit:
×
UNCOV
4928
  taosMemoryFree(res);
×
UNCOV
4929
  return code;
×
4930
}
4931

UNCOV
4932
int32_t elapsedCombine(SqlFunctionCtx* pDestCtx, SqlFunctionCtx* pSourceCtx) {
×
UNCOV
4933
  SResultRowEntryInfo* pDResInfo = GET_RES_INFO(pDestCtx);
×
UNCOV
4934
  SElapsedInfo*        pDBuf = GET_ROWCELL_INTERBUF(pDResInfo);
×
4935

UNCOV
4936
  SResultRowEntryInfo* pSResInfo = GET_RES_INFO(pSourceCtx);
×
UNCOV
4937
  SElapsedInfo*        pSBuf = GET_ROWCELL_INTERBUF(pSResInfo);
×
4938

UNCOV
4939
  elapsedTransferInfo(pSBuf, pDBuf);
×
UNCOV
4940
  pDResInfo->numOfRes = TMAX(pDResInfo->numOfRes, pSResInfo->numOfRes);
×
UNCOV
4941
  pDResInfo->isNullRes &= pSResInfo->isNullRes;
×
UNCOV
4942
  return TSDB_CODE_SUCCESS;
×
4943
}
4944

4945
int32_t getHistogramInfoSize() {
706,175✔
4946
  return (int32_t)sizeof(SHistoFuncInfo) + HISTOGRAM_MAX_BINS_NUM * sizeof(SHistoFuncBin);
706,175✔
4947
}
4948

4949
bool getHistogramFuncEnv(SFunctionNode* UNUSED_PARAM(pFunc), SFuncExecEnv* pEnv) {
1,283,964✔
4950
  pEnv->calcMemSize = sizeof(SHistoFuncInfo) + HISTOGRAM_MAX_BINS_NUM * sizeof(SHistoFuncBin);
1,283,964✔
4951
  return true;
1,286,065✔
4952
}
4953

4954
static int8_t getHistogramBinType(char* binTypeStr) {
880,700✔
4955
  int8_t binType;
4956
  if (strcasecmp(binTypeStr, "user_input") == 0) {
880,700✔
4957
    binType = USER_INPUT_BIN;
440,603✔
4958
  } else if (strcasecmp(binTypeStr, "linear_bin") == 0) {
440,097✔
4959
    binType = LINEAR_BIN;
125,124✔
4960
  } else if (strcasecmp(binTypeStr, "log_bin") == 0) {
314,973✔
4961
    binType = LOG_BIN;
314,459✔
4962
  } else {
4963
    binType = UNKNOWN_BIN;
514✔
4964
  }
4965

4966
  return binType;
880,700✔
4967
}
4968

4969
static int32_t getHistogramBinDesc(SHistoFuncInfo* pInfo, char* binDescStr, int8_t binType, bool normalized) {
880,700✔
4970
  cJSON*  binDesc = cJSON_Parse(binDescStr);
880,700✔
4971
  int32_t numOfBins;
4972
  double* intervals;
4973
  if (cJSON_IsObject(binDesc)) { /* linaer/log bins */
880,700✔
4974
    int32_t numOfParams = cJSON_GetArraySize(binDesc);
439,938✔
4975
    int32_t startIndex;
4976
    if (numOfParams != 4) {
439,583✔
UNCOV
4977
      cJSON_Delete(binDesc);
×
UNCOV
4978
      return TSDB_CODE_FAILED;
×
4979
    }
4980

4981
    cJSON* start = cJSON_GetObjectItem(binDesc, "start");
439,583✔
4982
    cJSON* factor = cJSON_GetObjectItem(binDesc, "factor");
439,583✔
4983
    cJSON* width = cJSON_GetObjectItem(binDesc, "width");
439,938✔
4984
    cJSON* count = cJSON_GetObjectItem(binDesc, "count");
439,938✔
4985
    cJSON* infinity = cJSON_GetObjectItem(binDesc, "infinity");
439,938✔
4986

4987
    if (!cJSON_IsNumber(start) || !cJSON_IsNumber(count) || !cJSON_IsBool(infinity)) {
439,938✔
4988
      cJSON_Delete(binDesc);
163✔
4989
      return TSDB_CODE_FAILED;
×
4990
    }
4991

4992
    if (count->valueint <= 0 || count->valueint > 1000) {  // limit count to 1000
439,065✔
UNCOV
4993
      cJSON_Delete(binDesc);
×
UNCOV
4994
      return TSDB_CODE_FAILED;
×
4995
    }
4996

4997
    if (isinf(start->valuedouble) || (width != NULL && isinf(width->valuedouble)) ||
439,583✔
4998
        (factor != NULL && isinf(factor->valuedouble)) || (count != NULL && isinf(count->valuedouble))) {
439,583✔
UNCOV
4999
      cJSON_Delete(binDesc);
×
UNCOV
5000
      return TSDB_CODE_FAILED;
×
5001
    }
5002

5003
    int32_t counter = (int32_t)count->valueint;
439,938✔
5004
    if (infinity->valueint == false) {
439,583✔
5005
      startIndex = 0;
148,608✔
5006
      numOfBins = counter + 1;
148,608✔
5007
    } else {
5008
      startIndex = 1;
290,975✔
5009
      numOfBins = counter + 3;
290,975✔
5010
    }
5011

5012
    intervals = taosMemoryCalloc(numOfBins, sizeof(double));
439,583✔
5013
    if (NULL == intervals) {
439,583✔
UNCOV
5014
      cJSON_Delete(binDesc);
×
UNCOV
5015
      qError("histogram function out of memory");
×
UNCOV
5016
      return terrno;
×
5017
    }
5018
    if (cJSON_IsNumber(width) && factor == NULL && binType == LINEAR_BIN) {
439,583✔
5019
      // linear bin process
5020
      if (width->valuedouble == 0) {
125,124✔
UNCOV
5021
        taosMemoryFree(intervals);
×
UNCOV
5022
        cJSON_Delete(binDesc);
×
UNCOV
5023
        return TSDB_CODE_FAILED;
×
5024
      }
5025
      for (int i = 0; i < counter + 1; ++i) {
576,716✔
5026
        intervals[startIndex] = start->valuedouble + i * width->valuedouble;
451,592✔
5027
        if (isinf(intervals[startIndex])) {
451,592✔
UNCOV
5028
          taosMemoryFree(intervals);
×
UNCOV
5029
          cJSON_Delete(binDesc);
×
UNCOV
5030
          return TSDB_CODE_FAILED;
×
5031
        }
5032
        startIndex++;
451,592✔
5033
      }
5034
    } else if (cJSON_IsNumber(factor) && width == NULL && binType == LOG_BIN) {
314,459✔
5035
      // log bin process
5036
      if (start->valuedouble == 0) {
314,814✔
5037
        taosMemoryFree(intervals);
×
UNCOV
5038
        cJSON_Delete(binDesc);
×
UNCOV
5039
        return TSDB_CODE_FAILED;
×
5040
      }
5041
      if (factor->valuedouble < 0 || factor->valuedouble == 0 || factor->valuedouble == 1) {
313,941✔
5042
        taosMemoryFree(intervals);
710✔
5043
        cJSON_Delete(binDesc);
×
UNCOV
5044
        return TSDB_CODE_FAILED;
×
5045
      }
5046
      for (int i = 0; i < counter + 1; ++i) {
1,904,899✔
5047
        intervals[startIndex] = start->valuedouble * pow(factor->valuedouble, i * 1.0);
1,590,603✔
5048
        if (isinf(intervals[startIndex])) {
1,590,958✔
5049
          taosMemoryFree(intervals);
×
5050
          cJSON_Delete(binDesc);
×
UNCOV
5051
          return TSDB_CODE_FAILED;
×
5052
        }
5053
        startIndex++;
1,590,795✔
5054
      }
5055
    } else {
5056
      taosMemoryFree(intervals);
×
UNCOV
5057
      cJSON_Delete(binDesc);
×
UNCOV
5058
      return TSDB_CODE_FAILED;
×
5059
    }
5060

5061
    if (infinity->valueint == true) {
439,420✔
5062
      intervals[0] = -INFINITY;
290,975✔
5063
      intervals[numOfBins - 1] = INFINITY;
290,975✔
5064
      // in case of desc bin orders, -inf/inf should be swapped
5065
      if (numOfBins < 4) {
290,975✔
UNCOV
5066
        return TSDB_CODE_FAILED;
×
5067
      }
5068
      if (intervals[1] > intervals[numOfBins - 2]) {
290,975✔
5069
        TSWAP(intervals[0], intervals[numOfBins - 1]);
240,510✔
5070
      }
5071
    }
5072
  } else if (cJSON_IsArray(binDesc)) { /* user input bins */
440,089✔
5073
    if (binType != USER_INPUT_BIN) {
441,117✔
UNCOV
5074
      cJSON_Delete(binDesc);
×
5075
      return TSDB_CODE_FAILED;
×
5076
    }
5077
    numOfBins = cJSON_GetArraySize(binDesc);
441,117✔
5078
    intervals = taosMemoryCalloc(numOfBins, sizeof(double));
441,117✔
5079
    if (NULL == intervals) {
440,089✔
UNCOV
5080
      cJSON_Delete(binDesc);
×
UNCOV
5081
      qError("histogram function out of memory");
×
UNCOV
5082
      return terrno;
×
5083
    }
5084
    cJSON* bin = binDesc->child;
440,089✔
5085
    if (bin == NULL) {
440,603✔
UNCOV
5086
      taosMemoryFree(intervals);
×
UNCOV
5087
      cJSON_Delete(binDesc);
×
UNCOV
5088
      return TSDB_CODE_FAILED;
×
5089
    }
5090
    int i = 0;
440,603✔
5091
    while (bin) {
1,907,291✔
5092
      intervals[i] = bin->valuedouble;
1,466,174✔
5093
      if (!cJSON_IsNumber(bin)) {
1,466,174✔
UNCOV
5094
        taosMemoryFree(intervals);
×
5095
        cJSON_Delete(binDesc);
×
UNCOV
5096
        return TSDB_CODE_FAILED;
×
5097
      }
5098
      if (i != 0 && intervals[i] <= intervals[i - 1]) {
1,466,174✔
UNCOV
5099
        taosMemoryFree(intervals);
×
UNCOV
5100
        cJSON_Delete(binDesc);
×
UNCOV
5101
        return TSDB_CODE_FAILED;
×
5102
      }
5103
      bin = bin->next;
1,466,174✔
5104
      i++;
1,466,688✔
5105
    }
5106
  } else {
UNCOV
5107
    cJSON_Delete(binDesc);
×
5108
    return TSDB_CODE_FAILED;
×
5109
  }
5110

5111
  pInfo->numOfBins = numOfBins - 1;
879,861✔
5112
  pInfo->normalized = normalized;
880,345✔
5113
  for (int32_t i = 0; i < pInfo->numOfBins; ++i) {
4,089,672✔
5114
    pInfo->bins[i].lower = intervals[i] < intervals[i + 1] ? intervals[i] : intervals[i + 1];
3,211,553✔
5115
    pInfo->bins[i].upper = intervals[i + 1] > intervals[i] ? intervals[i + 1] : intervals[i];
3,210,488✔
5116
    pInfo->bins[i].count = 0;
3,209,357✔
5117
  }
5118

5119
  taosMemoryFree(intervals);
878,282✔
5120
  cJSON_Delete(binDesc);
880,186✔
5121

5122
  return TSDB_CODE_SUCCESS;
880,345✔
5123
}
5124

5125
int32_t histogramFunctionSetup(SqlFunctionCtx* pCtx, SResultRowEntryInfo* pResultInfo) {
880,700✔
5126
  if (pResultInfo->initialized) {
880,700✔
5127
    return TSDB_CODE_SUCCESS;
×
5128
  }
5129
  if (TSDB_CODE_SUCCESS != functionSetup(pCtx, pResultInfo)) {
880,700✔
UNCOV
5130
    return TSDB_CODE_FUNC_SETUP_ERROR;
×
5131
  }
5132

5133
  SHistoFuncInfo* pInfo = GET_ROWCELL_INTERBUF(pResultInfo);
881,055✔
5134
  pInfo->numOfBins = 0;
881,055✔
5135
  pInfo->totalCount = 0;
881,055✔
5136
  pInfo->normalized = 0;
881,055✔
5137

5138
  char* binTypeStr = taosStrndup(varDataVal(pCtx->param[1].param.pz), varDataLen(pCtx->param[1].param.pz));
880,700✔
5139
  if (binTypeStr == NULL) {
880,700✔
UNCOV
5140
    return terrno;
×
5141
  }
5142
  int8_t binType = getHistogramBinType(binTypeStr);
880,700✔
5143
  taosMemoryFree(binTypeStr);
880,186✔
5144

5145
  if (binType == UNKNOWN_BIN) {
880,700✔
UNCOV
5146
    return TSDB_CODE_FUNC_FUNTION_PARA_VALUE;
×
5147
  }
5148
  char* binDesc = taosStrndup(varDataVal(pCtx->param[2].param.pz), varDataLen(pCtx->param[2].param.pz));
880,700✔
5149
  if (binDesc == NULL) {
880,186✔
UNCOV
5150
    return terrno;
×
5151
  }
5152
  int64_t normalized = pCtx->param[3].param.i;
880,186✔
5153
  if (normalized != 0 && normalized != 1) {
881,055✔
UNCOV
5154
    taosMemoryFree(binDesc);
×
UNCOV
5155
    return TSDB_CODE_FUNC_FUNTION_PARA_VALUE;
×
5156
  }
5157
  int32_t code = getHistogramBinDesc(pInfo, binDesc, binType, (bool)normalized);
881,055✔
5158
  if (TSDB_CODE_SUCCESS != code) {
880,345✔
UNCOV
5159
    taosMemoryFree(binDesc);
×
UNCOV
5160
    return code;
×
5161
  }
5162
  taosMemoryFree(binDesc);
880,345✔
5163

5164
  return TSDB_CODE_SUCCESS;
881,055✔
5165
}
5166

5167
static int32_t histogramFunctionImpl(SqlFunctionCtx* pCtx, bool isPartial) {
1,026,445✔
5168
  SHistoFuncInfo* pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
1,026,445✔
5169

5170
  SInputColumnInfoData* pInput = &pCtx->input;
1,027,155✔
5171
  SColumnInfoData*      pCol = pInput->pData[0];
1,026,445✔
5172

5173
  int32_t type = pInput->pData[0]->info.type;
1,026,800✔
5174

5175
  int32_t start = pInput->startRowIndex;
1,026,445✔
5176
  int32_t numOfRows = pInput->numOfRows;
1,026,641✔
5177

5178
  int32_t numOfElems = 0;
1,039,835✔
5179
  for (int32_t i = start; i < numOfRows + start; ++i) {
148,336,092✔
5180
    if (pCol->hasNull && colDataIsNull_f(pCol, i)) {
147,308,937✔
5181
      continue;
117,464,828✔
5182
    }
5183

5184
    numOfElems++;
29,838,074✔
5185

5186
    char*  data = colDataGetData(pCol, i);
29,838,074✔
5187
    double v;
5188
    GET_TYPED_DATA(v, double, type, data, typeGetTypeModFromColInfo(&pCol->info));
29,848,175✔
5189

5190
    for (int32_t k = 0; k < pInfo->numOfBins; ++k) {
56,562,585✔
5191
      if (v > pInfo->bins[k].lower && v <= pInfo->bins[k].upper) {
45,280,684✔
5192
        pInfo->bins[k].count++;
18,586,898✔
5193
        pInfo->totalCount++;
18,587,866✔
5194
        break;
18,590,286✔
5195
      }
5196
    }
5197
  }
5198

5199
  if (!isPartial) {
1,027,155✔
5200
    GET_RES_INFO(pCtx)->numOfRes = pInfo->numOfBins;
698,951✔
5201
  } else {
5202
    GET_RES_INFO(pCtx)->numOfRes = 1;
328,204✔
5203
  }
5204
  return TSDB_CODE_SUCCESS;
1,026,282✔
5205
}
5206

5207
int32_t histogramFunction(SqlFunctionCtx* pCtx) { return histogramFunctionImpl(pCtx, false); }
698,241✔
5208

5209
int32_t histogramFunctionPartial(SqlFunctionCtx* pCtx) { return histogramFunctionImpl(pCtx, true); }
328,204✔
5210

5211
static void histogramTransferInfo(SHistoFuncInfo* pInput, SHistoFuncInfo* pOutput) {
208,068✔
5212
  pOutput->normalized = pInput->normalized;
208,068✔
5213
  pOutput->numOfBins = pInput->numOfBins;
208,564✔
5214
  pOutput->totalCount += pInput->totalCount;
208,068✔
5215
  for (int32_t k = 0; k < pOutput->numOfBins; ++k) {
1,272,540✔
5216
    pOutput->bins[k].lower = pInput->bins[k].lower;
1,064,472✔
5217
    pOutput->bins[k].upper = pInput->bins[k].upper;
1,064,472✔
5218
    pOutput->bins[k].count += pInput->bins[k].count;
1,064,968✔
5219
  }
5220
}
208,068✔
5221

5222
int32_t histogramFunctionMerge(SqlFunctionCtx* pCtx) {
208,068✔
5223
  SInputColumnInfoData* pInput = &pCtx->input;
208,068✔
5224
  SColumnInfoData*      pCol = pInput->pData[0];
208,068✔
5225
  if (pCol->info.type != TSDB_DATA_TYPE_BINARY) {
208,068✔
UNCOV
5226
    return TSDB_CODE_FUNC_FUNTION_PARA_TYPE;
×
5227
  }
5228

5229
  SHistoFuncInfo* pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
208,564✔
5230

5231
  int32_t start = pInput->startRowIndex;
208,068✔
5232

5233
  for (int32_t i = start; i < start + pInput->numOfRows; ++i) {
416,632✔
5234
    char*           data = colDataGetData(pCol, i);
208,564✔
5235
    SHistoFuncInfo* pInputInfo = (SHistoFuncInfo*)varDataVal(data);
208,564✔
5236
    histogramTransferInfo(pInputInfo, pInfo);
208,068✔
5237
  }
5238

5239
  SET_VAL(GET_RES_INFO(pCtx), pInfo->numOfBins, pInfo->numOfBins);
208,564✔
5240
  return TSDB_CODE_SUCCESS;
208,564✔
5241
}
5242

5243
int32_t histogramFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
861,225✔
5244
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
861,225✔
5245
  SHistoFuncInfo*      pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
861,580✔
5246
  int32_t              slotId = pCtx->pExpr->base.resSchema.slotId;
861,580✔
5247
  SColumnInfoData*     pCol = taosArrayGet(pBlock->pDataBlock, slotId);
861,225✔
5248
  int32_t              code = TSDB_CODE_SUCCESS;
861,225✔
5249

5250
  int32_t currentRow = pBlock->info.rows;
861,225✔
5251
  if (NULL == pCol) {
861,225✔
UNCOV
5252
    return TSDB_CODE_OUT_OF_RANGE;
×
5253
  }
5254

5255
  if (pInfo->normalized) {
861,225✔
5256
    for (int32_t k = 0; k < pResInfo->numOfRes; ++k) {
2,342,024✔
5257
      if (pInfo->totalCount != 0) {
1,877,652✔
5258
        pInfo->bins[k].percentage = pInfo->bins[k].count / (double)pInfo->totalCount;
170,811✔
5259
      } else {
5260
        pInfo->bins[k].percentage = 0;
1,706,841✔
5261
      }
5262
    }
5263
  }
5264

5265
  for (int32_t i = 0; i < pResInfo->numOfRes; ++i) {
3,940,859✔
5266
    int32_t len;
5267
    char    buf[512] = {0};
3,078,924✔
5268
    if (!pInfo->normalized) {
3,078,214✔
5269
      len = tsnprintf(varDataVal(buf), sizeof(buf) - VARSTR_HEADER_SIZE,
1,200,562✔
5270
                      "{\"lower_bin\":%g, \"upper_bin\":%g, \"count\":%" PRId64 "}", pInfo->bins[i].lower,
5271
                      pInfo->bins[i].upper, pInfo->bins[i].count);
5272
    } else {
5273
      len = tsnprintf(varDataVal(buf), sizeof(buf) - VARSTR_HEADER_SIZE,
1,878,007✔
5274
                      "{\"lower_bin\":%g, \"upper_bin\":%g, \"count\":%lf}", pInfo->bins[i].lower, pInfo->bins[i].upper,
5275
                      pInfo->bins[i].percentage);
5276
    }
5277
    varDataSetLen(buf, len);
3,077,859✔
5278
    code = colDataSetVal(pCol, currentRow, buf, false);
3,078,214✔
5279
    if (TSDB_CODE_SUCCESS != code) {
3,077,859✔
UNCOV
5280
      return code;
×
5281
    }
5282
    currentRow++;
3,077,859✔
5283
  }
5284

5285
  return code;
861,580✔
5286
}
5287

5288
int32_t histogramPartialFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
208,564✔
5289
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
208,564✔
5290
  SHistoFuncInfo*      pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
208,564✔
5291
  int32_t              resultBytes = getHistogramInfoSize();
208,564✔
5292
  char*                res = taosMemoryCalloc(resultBytes + VARSTR_HEADER_SIZE, sizeof(char));
208,564✔
5293

5294
  if (NULL == res) {
208,564✔
UNCOV
5295
    return terrno;
×
5296
  }
5297
  (void)memcpy(varDataVal(res), pInfo, resultBytes);
208,564✔
5298
  varDataSetLen(res, resultBytes);
208,564✔
5299

5300
  int32_t          slotId = pCtx->pExpr->base.resSchema.slotId;
208,564✔
5301
  int32_t          code = TSDB_CODE_SUCCESS;
208,564✔
5302
  SColumnInfoData* pCol = taosArrayGet(pBlock->pDataBlock, slotId);
208,564✔
5303
  if (NULL == pCol) {
208,564✔
UNCOV
5304
    code = terrno;
×
UNCOV
5305
    goto _exit;
×
5306
  }
5307
  code = colDataSetVal(pCol, pBlock->info.rows, res, false);
208,564✔
5308

5309
_exit:
208,564✔
5310
  taosMemoryFree(res);
208,564✔
5311
  return code;
208,564✔
5312
}
5313

UNCOV
5314
int32_t histogramCombine(SqlFunctionCtx* pDestCtx, SqlFunctionCtx* pSourceCtx) {
×
UNCOV
5315
  SResultRowEntryInfo* pDResInfo = GET_RES_INFO(pDestCtx);
×
UNCOV
5316
  SHistoFuncInfo*      pDBuf = GET_ROWCELL_INTERBUF(pDResInfo);
×
5317

UNCOV
5318
  SResultRowEntryInfo* pSResInfo = GET_RES_INFO(pSourceCtx);
×
UNCOV
5319
  SHistoFuncInfo*      pSBuf = GET_ROWCELL_INTERBUF(pSResInfo);
×
5320

UNCOV
5321
  histogramTransferInfo(pSBuf, pDBuf);
×
UNCOV
5322
  pDResInfo->numOfRes = TMAX(pDResInfo->numOfRes, pSResInfo->numOfRes);
×
UNCOV
5323
  pDResInfo->isNullRes &= pSResInfo->isNullRes;
×
UNCOV
5324
  return TSDB_CODE_SUCCESS;
×
5325
}
5326

5327
int32_t getHLLInfoSize() { return (int32_t)sizeof(SHLLInfo); }
247,733✔
5328

5329
bool getHLLFuncEnv(SFunctionNode* UNUSED_PARAM(pFunc), SFuncExecEnv* pEnv) {
3,668,590✔
5330
  pEnv->calcMemSize = sizeof(SHLLInfo);
3,668,590✔
5331
  return true;
3,670,114✔
5332
}
5333

5334
static uint8_t hllCountNum(void* data, int32_t bytes, int32_t* buk) {
545,255,384✔
5335
  uint64_t hash = MurmurHash3_64(data, bytes);
545,255,384✔
5336
  int32_t  index = hash & HLL_BUCKET_MASK;
545,268,306✔
5337
  hash >>= HLL_BUCKET_BITS;
545,268,306✔
5338
  hash |= ((uint64_t)1 << HLL_DATA_BITS);
545,268,306✔
5339
  uint64_t bit = 1;
545,268,306✔
5340
  uint8_t  count = 1;
545,268,306✔
5341
  while ((hash & bit) == 0) {
1,156,562,022✔
5342
    count++;
611,293,716✔
5343
    bit <<= 1;
611,293,716✔
5344
  }
5345
  *buk = index;
545,268,306✔
5346
  return count;
545,268,828✔
5347
}
5348

5349
static void hllBucketHisto(uint8_t* buckets, int32_t* bucketHisto) {
8,772,985✔
5350
  uint64_t* word = (uint64_t*)buckets;
8,772,985✔
5351
  uint8_t*  bytes;
5352

5353
  for (int32_t j = 0; j < HLL_BUCKETS >> 3; j++) {
2,147,483,647✔
5354
    if (*word == 0) {
2,147,483,647✔
5355
      bucketHisto[0] += 8;
2,147,483,647✔
5356
    } else {
5357
      bytes = (uint8_t*)word;
29,740,435✔
5358
      bucketHisto[bytes[0]]++;
29,740,435✔
5359
      bucketHisto[bytes[1]]++;
47,319,941✔
5360
      bucketHisto[bytes[2]]++;
47,319,941✔
5361
      bucketHisto[bytes[3]]++;
47,319,941✔
5362
      bucketHisto[bytes[4]]++;
47,319,941✔
5363
      bucketHisto[bytes[5]]++;
47,319,941✔
5364
      bucketHisto[bytes[6]]++;
47,319,941✔
5365
      bucketHisto[bytes[7]]++;
47,319,941✔
5366
    }
5367
    word++;
2,147,483,647✔
5368
  }
5369
}
10,959✔
5370
static double hllTau(double x) {
8,772,985✔
5371
  if (x == 0. || x == 1.) return 0.;
8,772,985✔
5372
  double zPrime;
UNCOV
5373
  double y = 1.0;
×
UNCOV
5374
  double z = 1 - x;
×
5375
  do {
UNCOV
5376
    x = sqrt(x);
×
UNCOV
5377
    zPrime = z;
×
UNCOV
5378
    y *= 0.5;
×
UNCOV
5379
    z -= pow(1 - x, 2) * y;
×
UNCOV
5380
  } while (zPrime != z);
×
UNCOV
5381
  return z / 3;
×
5382
}
5383

5384
static double hllSigma(double x) {
8,772,985✔
5385
  if (x == 1.0) return INFINITY;
8,772,985✔
5386
  double zPrime;
5387
  double y = 1;
4,868,601✔
5388
  double z = x;
4,868,601✔
5389
  do {
5390
    x *= x;
95,507,392✔
5391
    zPrime = z;
95,507,392✔
5392
    z += x * y;
95,507,392✔
5393
    y += y;
95,507,392✔
5394
  } while (zPrime != z);
95,507,392✔
5395
  return z;
4,868,601✔
5396
}
5397

5398
// estimate the cardinality, the algorithm refer this paper: "New cardinality estimation algorithms for HyperLogLog
5399
// sketches"
5400
static uint64_t hllCountCnt(uint8_t* buckets) {
8,772,985✔
5401
  double  m = HLL_BUCKETS;
8,772,985✔
5402
  int32_t buckethisto[64] = {0};
8,772,985✔
5403
  hllBucketHisto(buckets, buckethisto);
8,772,985✔
5404

5405
  double z = m * hllTau((m - buckethisto[HLL_DATA_BITS + 1]) / (double)m);
8,772,985✔
5406
  for (int j = HLL_DATA_BITS; j >= 1; --j) {
447,383,171✔
5407
    z += buckethisto[j];
438,610,186✔
5408
    z *= 0.5;
438,610,186✔
5409
  }
5410

5411
  z += m * hllSigma(buckethisto[0] / (double)m);
8,772,985✔
5412
  double E = (double)llroundl(HLL_ALPHA_INF * m * m / z);
8,772,985✔
5413

5414
  return (uint64_t)E;
8,772,985✔
5415
}
5416

5417
int32_t hllFunction(SqlFunctionCtx* pCtx) {
9,024,438✔
5418
  SHLLInfo* pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
9,024,438✔
5419

5420
  SInputColumnInfoData* pInput = &pCtx->input;
9,022,382✔
5421
  SColumnInfoData*      pCol = pInput->pData[0];
9,023,924✔
5422

5423
  int32_t type = pCol->info.type;
9,023,924✔
5424
  int32_t bytes = pCol->info.bytes;
9,022,892✔
5425

5426
  int32_t start = pInput->startRowIndex;
9,020,990✔
5427
  int32_t numOfRows = pInput->numOfRows;
9,024,592✔
5428

5429
  int32_t numOfElems = 0;
9,021,342✔
5430
  if (IS_NULL_TYPE(type)) {
9,021,342✔
5431
    goto _hll_over;
132,505✔
5432
  }
5433

5434
  for (int32_t i = start; i < numOfRows + start; ++i) {
741,006,281✔
5435
    if (pCol->hasNull && colDataIsNull_s(pCol, i)) {
927,912,272✔
5436
      continue;
186,861,724✔
5437
    }
5438

5439
    numOfElems++;
545,248,870✔
5440

5441
    char* data = colDataGetData(pCol, i);
545,248,870✔
5442
    if (IS_VAR_DATA_TYPE(type)) {
545,265,214✔
5443
      if (IS_STR_DATA_BLOB(type)) {
80,488,782✔
UNCOV
5444
        bytes = blobDataLen(data);
×
UNCOV
5445
        data = blobDataVal(data);
×
5446
      } else {
5447
        bytes = varDataLen(data);
80,488,782✔
5448
        data = varDataVal(data);
80,487,746✔
5449
      }
5450
    }
5451

5452
    int32_t index = 0;
545,264,178✔
5453
    uint8_t count = hllCountNum(data, bytes, &index);
545,262,106✔
5454
    uint8_t oldcount = pInfo->buckets[index];
545,266,760✔
5455
    if (count > oldcount) {
545,267,796✔
5456
      pInfo->buckets[index] = count;
97,138,295✔
5457
    }
5458
  }
5459

5460
_hll_over:
8,885,097✔
5461
  pInfo->totalCount += numOfElems;
9,017,602✔
5462

5463
  if (pInfo->totalCount == 0 && !tsCountAlwaysReturnValue) {
9,022,896✔
5464
    SET_VAL(GET_RES_INFO(pCtx), 0, 1);
236,829✔
5465
  } else {
5466
    SET_VAL(GET_RES_INFO(pCtx), 1, 1);
8,788,123✔
5467
  }
5468

5469
  return TSDB_CODE_SUCCESS;
9,024,952✔
5470
}
5471

5472
static void hllTransferInfo(SHLLInfo* pInput, SHLLInfo* pOutput) {
247,733✔
5473
  for (int32_t k = 0; k < HLL_BUCKETS; ++k) {
2,147,483,647✔
5474
    if (pOutput->buckets[k] < pInput->buckets[k]) {
2,147,483,647✔
5475
      pOutput->buckets[k] = pInput->buckets[k];
40,254,150✔
5476
    }
5477
  }
5478
  pOutput->totalCount += pInput->totalCount;
121,601✔
5479
}
247,733✔
5480

5481
int32_t hllFunctionMerge(SqlFunctionCtx* pCtx) {
247,733✔
5482
  SInputColumnInfoData* pInput = &pCtx->input;
247,733✔
5483
  SColumnInfoData*      pCol = pInput->pData[0];
247,733✔
5484

5485
  if (IS_NULL_TYPE(pCol->info.type)) {
247,733✔
UNCOV
5486
    SET_VAL(GET_RES_INFO(pCtx), 0, 1);
×
UNCOV
5487
    return TSDB_CODE_SUCCESS;
×
5488
  }
5489

5490
  if (pCol->info.type != TSDB_DATA_TYPE_BINARY) {
247,733✔
UNCOV
5491
    return TSDB_CODE_SUCCESS;
×
5492
  }
5493

5494
  SHLLInfo* pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
247,733✔
5495

5496
  int32_t start = pInput->startRowIndex;
247,733✔
5497

5498
  for (int32_t i = start; i < start + pInput->numOfRows; ++i) {
495,466✔
5499
    if (colDataIsNull_s(pCol, i)) continue;
495,466✔
5500
    char*     data = colDataGetData(pCol, i);
247,733✔
5501
    SHLLInfo* pInputInfo = (SHLLInfo*)varDataVal(data);
247,733✔
5502
    hllTransferInfo(pInputInfo, pInfo);
247,733✔
5503
  }
5504

5505
  if (pInfo->totalCount == 0 && !tsCountAlwaysReturnValue) {
247,733✔
5506
    SET_VAL(GET_RES_INFO(pCtx), 0, 1);
69✔
5507
  } else {
5508
    SET_VAL(GET_RES_INFO(pCtx), 1, 1);
247,664✔
5509
  }
5510

5511
  return TSDB_CODE_SUCCESS;
247,733✔
5512
}
5513

5514
int32_t hllFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
8,772,985✔
5515
  SResultRowEntryInfo* pInfo = GET_RES_INFO(pCtx);
8,772,985✔
5516

5517
  SHLLInfo* pHllInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
8,772,985✔
5518
  pHllInfo->result = hllCountCnt(pHllInfo->buckets);
8,772,985✔
5519
  if (tsCountAlwaysReturnValue && pHllInfo->result == 0) {
8,772,471✔
5520
    pInfo->numOfRes = 1;
3,668,038✔
5521
  }
5522

5523
  return functionFinalize(pCtx, pBlock);
8,772,471✔
5524
}
5525

5526
int32_t hllPartialFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
247,733✔
5527
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
247,733✔
5528
  SHLLInfo*            pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
247,733✔
5529
  int32_t              resultBytes = getHLLInfoSize();
247,733✔
5530
  char*                res = taosMemoryCalloc(resultBytes + VARSTR_HEADER_SIZE, sizeof(char));
247,733✔
5531

5532
  if (NULL == res) {
247,733✔
UNCOV
5533
    return terrno;
×
5534
  }
5535
  (void)memcpy(varDataVal(res), pInfo, resultBytes);
247,733✔
5536
  varDataSetLen(res, resultBytes);
247,733✔
5537

5538
  int32_t          slotId = pCtx->pExpr->base.resSchema.slotId;
247,733✔
5539
  int32_t          code = TSDB_CODE_SUCCESS;
247,733✔
5540
  SColumnInfoData* pCol = taosArrayGet(pBlock->pDataBlock, slotId);
247,733✔
5541
  if (NULL == pCol) {
247,373✔
UNCOV
5542
    code = terrno;
×
UNCOV
5543
    goto _exit;
×
5544
  }
5545

5546
  code = colDataSetVal(pCol, pBlock->info.rows, res, false);
247,373✔
5547

5548
_exit:
247,733✔
5549
  taosMemoryFree(res);
247,733✔
5550
  return code;
247,733✔
5551
}
5552

UNCOV
5553
int32_t hllCombine(SqlFunctionCtx* pDestCtx, SqlFunctionCtx* pSourceCtx) {
×
5554
  SResultRowEntryInfo* pDResInfo = GET_RES_INFO(pDestCtx);
×
UNCOV
5555
  SHLLInfo*            pDBuf = GET_ROWCELL_INTERBUF(pDResInfo);
×
5556

UNCOV
5557
  SResultRowEntryInfo* pSResInfo = GET_RES_INFO(pSourceCtx);
×
UNCOV
5558
  SHLLInfo*            pSBuf = GET_ROWCELL_INTERBUF(pSResInfo);
×
5559

UNCOV
5560
  hllTransferInfo(pSBuf, pDBuf);
×
UNCOV
5561
  pDResInfo->numOfRes = TMAX(pDResInfo->numOfRes, pSResInfo->numOfRes);
×
UNCOV
5562
  pDResInfo->isNullRes &= pSResInfo->isNullRes;
×
UNCOV
5563
  return TSDB_CODE_SUCCESS;
×
5564
}
5565

5566
bool getStateFuncEnv(SFunctionNode* UNUSED_PARAM(pFunc), SFuncExecEnv* pEnv) {
1,263,217✔
5567
  pEnv->calcMemSize = sizeof(SStateInfo);
1,263,217✔
5568
  return true;
1,263,217✔
5569
}
5570

5571
static int8_t getStateOpType(char* opStr) {
1,284,883✔
5572
  int8_t opType;
5573
  if (strncasecmp(opStr, "LT", 2) == 0) {
1,284,883✔
5574
    opType = STATE_OPER_LT;
386,792✔
5575
  } else if (strncasecmp(opStr, "GT", 2) == 0) {
898,091✔
5576
    opType = STATE_OPER_GT;
434,437✔
5577
  } else if (strncasecmp(opStr, "LE", 2) == 0) {
463,654✔
5578
    opType = STATE_OPER_LE;
107,600✔
5579
  } else if (strncasecmp(opStr, "GE", 2) == 0) {
356,054✔
5580
    opType = STATE_OPER_GE;
105,802✔
5581
  } else if (strncasecmp(opStr, "NE", 2) == 0) {
250,252✔
5582
    opType = STATE_OPER_NE;
104,072✔
5583
  } else if (strncasecmp(opStr, "EQ", 2) == 0) {
146,180✔
5584
    opType = STATE_OPER_EQ;
146,180✔
5585
  } else {
5586
    opType = STATE_OPER_INVALID;
×
5587
  }
5588

5589
  return opType;
1,284,883✔
5590
}
5591

5592
static bool checkStateOp(int8_t op, SColumnInfoData* pCol, int32_t index, SVariant param) {
91,526,820✔
5593
  char* data = colDataGetData(pCol, index);
91,526,820✔
5594
  switch (pCol->info.type) {
91,527,180✔
5595
    case TSDB_DATA_TYPE_TINYINT: {
3,743,796✔
5596
      int8_t v = *(int8_t*)data;
3,743,796✔
5597
      STATE_COMP(op, v, param);
3,743,796✔
UNCOV
5598
      break;
×
5599
    }
5600
    case TSDB_DATA_TYPE_UTINYINT: {
32,558,464✔
5601
      uint8_t v = *(uint8_t*)data;
32,558,464✔
5602
      STATE_COMP(op, v, param);
32,558,464✔
UNCOV
5603
      break;
×
5604
    }
5605
    case TSDB_DATA_TYPE_SMALLINT: {
2,882,392✔
5606
      int16_t v = *(int16_t*)data;
2,882,392✔
5607
      STATE_COMP(op, v, param);
2,882,392✔
UNCOV
5608
      break;
×
5609
    }
5610
    case TSDB_DATA_TYPE_USMALLINT: {
593,280✔
5611
      uint16_t v = *(uint16_t*)data;
593,280✔
5612
      STATE_COMP(op, v, param);
593,280✔
5613
      break;
×
5614
    }
5615
    case TSDB_DATA_TYPE_INT: {
27,898,925✔
5616
      int32_t v = *(int32_t*)data;
27,898,925✔
5617
      STATE_COMP(op, v, param);
27,898,925✔
UNCOV
5618
      break;
×
5619
    }
5620
    case TSDB_DATA_TYPE_UINT: {
593,280✔
5621
      uint32_t v = *(uint32_t*)data;
593,280✔
5622
      STATE_COMP(op, v, param);
593,280✔
UNCOV
5623
      break;
×
5624
    }
5625
    case TSDB_DATA_TYPE_BIGINT: {
20,632,678✔
5626
      int64_t v = *(int64_t*)data;
20,632,678✔
5627
      STATE_COMP(op, v, param);
20,632,678✔
UNCOV
5628
      break;
×
5629
    }
5630
    case TSDB_DATA_TYPE_UBIGINT: {
593,280✔
5631
      uint64_t v = *(uint64_t*)data;
593,280✔
5632
      STATE_COMP(op, v, param);
593,280✔
UNCOV
5633
      break;
×
5634
    }
5635
    case TSDB_DATA_TYPE_FLOAT: {
1,118,392✔
5636
      float v = *(float*)data;
1,118,392✔
5637
      STATE_COMP(op, v, param);
1,118,392✔
UNCOV
5638
      break;
×
5639
    }
5640
    case TSDB_DATA_TYPE_DOUBLE: {
912,693✔
5641
      double v = *(double*)data;
912,693✔
5642
      STATE_COMP(op, v, param);
912,693✔
UNCOV
5643
      break;
×
5644
    }
UNCOV
5645
    default: {
×
UNCOV
5646
      return false;
×
5647
    }
5648
  }
UNCOV
5649
  return false;
×
5650
}
5651

5652
int32_t stateCountFunction(SqlFunctionCtx* pCtx) {
293,798✔
5653
  int32_t              code = TSDB_CODE_SUCCESS;
293,798✔
5654
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
293,798✔
5655
  SStateInfo*          pInfo = GET_ROWCELL_INTERBUF(pResInfo);
293,443✔
5656

5657
  SInputColumnInfoData* pInput = &pCtx->input;
293,798✔
5658
  TSKEY*                tsList = (int64_t*)pInput->pPTS->pData;
293,798✔
5659

5660
  SColumnInfoData* pInputCol = pInput->pData[0];
293,798✔
5661

5662
  int32_t          numOfElems = 0;
293,798✔
5663
  SColumnInfoData* pOutput = (SColumnInfoData*)pCtx->pOutput;
293,798✔
5664

5665
  int8_t op = getStateOpType(varDataVal(pCtx->param[1].param.pz));
293,798✔
5666
  if (STATE_OPER_INVALID == op) {
293,443✔
UNCOV
5667
    return 0;
×
5668
  }
5669

5670
  for (int32_t i = pInput->startRowIndex; i < pInput->numOfRows + pInput->startRowIndex; i += 1) {
73,803,638✔
5671
    if (pInfo->isPrevTsSet == true && tsList[i] == pInfo->prevTs) {
73,510,995✔
5672
      return TSDB_CODE_FUNC_DUP_TIMESTAMP;
800✔
5673
    } else {
5674
      pInfo->prevTs = tsList[i];
73,509,840✔
5675
    }
5676

5677
    pInfo->isPrevTsSet = true;
73,509,485✔
5678
    numOfElems++;
73,509,130✔
5679

5680
    if (colDataIsNull_f(pInputCol, i)) {
73,509,130✔
5681
      colDataSetNULL(pOutput, i);
39,027,082✔
5682
      // handle selectivity
5683
      if (pCtx->subsidiaries.num > 0) {
39,028,857✔
5684
        code = appendSelectivityValue(pCtx, i, pCtx->offset + numOfElems - 1);
3,753✔
5685
        if (TSDB_CODE_SUCCESS != code) {
3,398✔
UNCOV
5686
          return code;
×
5687
        }
5688
      }
5689
      continue;
39,027,437✔
5690
    }
5691

5692
    bool ret = checkStateOp(op, pInputCol, i, pCtx->param[2].param);
34,482,403✔
5693

5694
    int64_t output = -1;
34,482,403✔
5695
    if (ret) {
34,482,403✔
5696
      output = ++pInfo->count;
17,025,184✔
5697
    } else {
5698
      pInfo->count = 0;
17,457,219✔
5699
    }
5700
    code = colDataSetVal(pOutput, pCtx->offset + numOfElems - 1, (char*)&output, false);
34,482,403✔
5701
    if (TSDB_CODE_SUCCESS != code) {
34,482,403✔
UNCOV
5702
      return code;
×
5703
    }
5704

5705
    // handle selectivity
5706
    if (pCtx->subsidiaries.num > 0) {
34,482,403✔
5707
      code = appendSelectivityValue(pCtx, i, pCtx->offset + numOfElems - 1);
794,492✔
5708
      if (TSDB_CODE_SUCCESS != code) {
794,492✔
UNCOV
5709
        return code;
×
5710
      }
5711
    }
5712
  }
5713

5714
  pResInfo->numOfRes = numOfElems;
292,998✔
5715
  return TSDB_CODE_SUCCESS;
292,998✔
5716
}
5717

5718
int32_t stateDurationFunction(SqlFunctionCtx* pCtx) {
991,085✔
5719
  int32_t              code = TSDB_CODE_SUCCESS;
991,085✔
5720
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
991,085✔
5721
  SStateInfo*          pInfo = GET_ROWCELL_INTERBUF(pResInfo);
991,085✔
5722

5723
  SInputColumnInfoData* pInput = &pCtx->input;
991,085✔
5724
  TSKEY*                tsList = (int64_t*)pInput->pPTS->pData;
991,085✔
5725

5726
  SColumnInfoData* pInputCol = pInput->pData[0];
991,085✔
5727

5728
  int32_t          numOfElems = 0;
991,085✔
5729
  SColumnInfoData* pOutput = (SColumnInfoData*)pCtx->pOutput;
991,085✔
5730

5731
  // TODO: process timeUnit for different db precisions
5732
  int32_t timeUnit = 1;
991,085✔
5733
  if (pCtx->numOfParams == 5) {  // TODO: param number incorrect
991,085✔
5734
    timeUnit = pCtx->param[3].param.i;
787,543✔
5735
  }
5736

5737
  int8_t op = getStateOpType(varDataVal(pCtx->param[1].param.pz));
991,085✔
5738
  if (STATE_OPER_INVALID == op) {
991,085✔
UNCOV
5739
    return TSDB_CODE_INVALID_PARA;
×
5740
  }
5741

5742
  for (int32_t i = pInput->startRowIndex; i < pInput->numOfRows + pInput->startRowIndex; i += 1) {
93,449,722✔
5743
    if (pInfo->isPrevTsSet == true && tsList[i] == pInfo->prevTs) {
92,459,437✔
5744
      return TSDB_CODE_FUNC_DUP_TIMESTAMP;
800✔
5745
    } else {
5746
      pInfo->prevTs = tsList[i];
92,458,141✔
5747
    }
5748

5749
    pInfo->isPrevTsSet = true;
92,458,637✔
5750
    numOfElems++;
92,458,141✔
5751

5752
    if (colDataIsNull_f(pInputCol, i)) {
92,458,141✔
5753
      colDataSetNULL(pOutput, i);
35,414,852✔
5754
      // handle selectivity
5755
      if (pCtx->subsidiaries.num > 0) {
35,416,340✔
5756
        code = appendSelectivityValue(pCtx, i, pCtx->offset + numOfElems - 1);
7,277✔
5757
        if (TSDB_CODE_SUCCESS != code) {
7,277✔
UNCOV
5758
          return code;
×
5759
        }
5760
      }
5761
      continue;
35,416,340✔
5762
    }
5763

5764
    bool    ret = checkStateOp(op, pInputCol, i, pCtx->param[2].param);
57,044,777✔
5765
    int64_t output = -1;
57,044,777✔
5766
    if (ret) {
57,044,777✔
5767
      if (pInfo->durationStart == 0) {
26,866,691✔
5768
        output = 0;
6,273,611✔
5769
        pInfo->durationStart = tsList[i];
6,273,611✔
5770
      } else {
5771
        output = (tsList[i] - pInfo->durationStart) / timeUnit;
20,593,080✔
5772
      }
5773
    } else {
5774
      pInfo->durationStart = 0;
30,178,086✔
5775
    }
5776
    code = colDataSetVal(pOutput, pCtx->offset + numOfElems - 1, (char*)&output, false);
57,044,777✔
5777
    if (TSDB_CODE_SUCCESS != code) {
57,044,777✔
UNCOV
5778
      return code;
×
5779
    }
5780

5781
    // handle selectivity
5782
    if (pCtx->subsidiaries.num > 0) {
57,044,777✔
5783
      code = appendSelectivityValue(pCtx, i, pCtx->offset + numOfElems - 1);
90,380✔
5784
      if (TSDB_CODE_SUCCESS != code) {
90,380✔
UNCOV
5785
        return code;
×
5786
      }
5787
    }
5788
  }
5789

5790
  pResInfo->numOfRes = numOfElems;
990,285✔
5791
  return TSDB_CODE_SUCCESS;
990,285✔
5792
}
5793

5794
bool getCsumFuncEnv(SFunctionNode* UNUSED_PARAM(pFunc), SFuncExecEnv* pEnv) {
630,584✔
5795
  pEnv->calcMemSize = sizeof(SSumRes);
630,584✔
5796
  return true;
630,584✔
5797
}
5798

5799
int32_t csumFunction(SqlFunctionCtx* pCtx) {
707,344✔
5800
  int32_t              code = TSDB_CODE_SUCCESS;
707,344✔
5801
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
707,344✔
5802
  SSumRes*             pSumRes = GET_ROWCELL_INTERBUF(pResInfo);
707,840✔
5803

5804
  SInputColumnInfoData* pInput = &pCtx->input;
707,840✔
5805
  TSKEY*                tsList = (int64_t*)pInput->pPTS->pData;
707,344✔
5806

5807
  SColumnInfoData* pInputCol = pInput->pData[0];
707,840✔
5808
  SColumnInfoData* pOutput = (SColumnInfoData*)pCtx->pOutput;
706,848✔
5809

5810
  int32_t numOfElems = 0;
707,344✔
5811
  int32_t type = pInputCol->info.type;
707,344✔
5812
  int32_t startOffset = pCtx->offset;
707,840✔
5813
  for (int32_t i = pInput->startRowIndex; i < pInput->numOfRows + pInput->startRowIndex; i += 1) {
118,037,780✔
5814
    if (pSumRes->isPrevTsSet == true && tsList[i] == pSumRes->prevTs) {
117,296,859✔
5815
      return TSDB_CODE_FUNC_DUP_TIMESTAMP;
6,813✔
5816
    } else {
5817
      pSumRes->prevTs = tsList[i];
117,289,195✔
5818
    }
5819
    pSumRes->isPrevTsSet = true;
117,287,634✔
5820

5821
    int32_t pos = startOffset + numOfElems;
117,288,485✔
5822
    if (colDataIsNull_f(pInputCol, i)) {
117,288,485✔
5823
      // colDataSetNULL(pOutput, i);
5824
      continue;
56,204,586✔
5825
    }
5826

5827
    char* data = colDataGetData(pInputCol, i);
61,125,850✔
5828
    if (IS_SIGNED_NUMERIC_TYPE(type)) {
93,265,190✔
5829
      int64_t v;
5830
      GET_TYPED_DATA(v, int64_t, type, data, typeGetTypeModFromColInfo(&pInputCol->info));
32,139,340✔
5831
      pSumRes->isum += v;
32,139,340✔
5832
      code = colDataSetVal(pOutput, pos, (char*)&pSumRes->isum, false);
32,139,340✔
5833
      if (TSDB_CODE_SUCCESS != code) {
32,139,340✔
UNCOV
5834
        return code;
×
5835
      }
5836
    } else if (IS_UNSIGNED_NUMERIC_TYPE(type)) {
38,179,396✔
5837
      uint64_t v;
5838
      GET_TYPED_DATA(v, uint64_t, type, data, typeGetTypeModFromColInfo(&pInputCol->info));
9,192,886✔
5839
      pSumRes->usum += v;
9,192,886✔
5840
      code = colDataSetVal(pOutput, pos, (char*)&pSumRes->usum, false);
9,192,886✔
5841
      if (TSDB_CODE_SUCCESS != code) {
9,192,886✔
UNCOV
5842
        return code;
×
5843
      }
5844
    } else if (IS_FLOAT_TYPE(type)) {
19,793,624✔
5845
      double v;
5846
      GET_TYPED_DATA(v, double, type, data, typeGetTypeModFromColInfo(&pInputCol->info));
19,793,624✔
5847
      pSumRes->dsum += v;
19,793,624✔
5848
      // check for overflow
5849
      if (isinf(pSumRes->dsum) || isnan(pSumRes->dsum)) {
19,793,624✔
5850
        colDataSetNULL(pOutput, pos);
838✔
5851
      } else {
5852
        code = colDataSetVal(pOutput, pos, (char*)&pSumRes->dsum, false);
19,792,786✔
5853
        if (TSDB_CODE_SUCCESS != code) {
19,792,786✔
UNCOV
5854
          return code;
×
5855
        }
5856
      }
5857
    }
5858

5859
    // handle selectivity
5860
    if (pCtx->subsidiaries.num > 0) {
61,125,850✔
5861
      code = appendSelectivityValue(pCtx, i, pos);
21,512✔
5862
      if (TSDB_CODE_SUCCESS != code) {
21,512✔
UNCOV
5863
        return code;
×
5864
      }
5865
    }
5866

5867
    numOfElems++;
61,125,850✔
5868
  }
5869

5870
  pResInfo->numOfRes = numOfElems;
701,027✔
5871
  return TSDB_CODE_SUCCESS;
701,027✔
5872
}
5873

5874
bool getMavgFuncEnv(SFunctionNode* UNUSED_PARAM(pFunc), SFuncExecEnv* pEnv) {
366,660✔
5875
  pEnv->calcMemSize = sizeof(SMavgInfo) + MAVG_MAX_POINTS_NUM * sizeof(double);
366,660✔
5876
  return true;
366,660✔
5877
}
5878

5879
int32_t mavgFunctionSetup(SqlFunctionCtx* pCtx, SResultRowEntryInfo* pResultInfo) {
818,100✔
5880
  if (pResultInfo->initialized) {
818,100✔
5881
    return TSDB_CODE_SUCCESS;
364,936✔
5882
  }
5883
  if (TSDB_CODE_SUCCESS != functionSetup(pCtx, pResultInfo)) {
453,164✔
UNCOV
5884
    return TSDB_CODE_FUNC_SETUP_ERROR;
×
5885
  }
5886

5887
  SMavgInfo* pInfo = GET_ROWCELL_INTERBUF(pResultInfo);
453,164✔
5888
  pInfo->pos = 0;
453,164✔
5889
  pInfo->sum = 0;
453,164✔
5890
  pInfo->prevTs = -1;
453,164✔
5891
  pInfo->isPrevTsSet = false;
453,164✔
5892
  pInfo->numOfPoints = pCtx->param[1].param.i;
453,164✔
5893
  if (pInfo->numOfPoints < 1 || pInfo->numOfPoints > MAVG_MAX_POINTS_NUM) {
453,164✔
UNCOV
5894
    return TSDB_CODE_FUNC_FUNTION_PARA_VALUE;
×
5895
  }
5896
  pInfo->pointsMeet = false;
453,164✔
5897

5898
  return TSDB_CODE_SUCCESS;
453,164✔
5899
}
5900

5901
int32_t mavgFunction(SqlFunctionCtx* pCtx) {
451,440✔
5902
  int32_t              code = TSDB_CODE_SUCCESS;
451,440✔
5903
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
451,440✔
5904
  SMavgInfo*           pInfo = GET_ROWCELL_INTERBUF(pResInfo);
451,440✔
5905

5906
  SInputColumnInfoData* pInput = &pCtx->input;
451,440✔
5907
  TSKEY*                tsList = (int64_t*)pInput->pPTS->pData;
451,440✔
5908

5909
  SColumnInfoData* pInputCol = pInput->pData[0];
451,440✔
5910
  SColumnInfoData* pTsOutput = pCtx->pTsOutput;
451,440✔
5911
  SColumnInfoData* pOutput = (SColumnInfoData*)pCtx->pOutput;
451,440✔
5912

5913
  int32_t numOfElems = 0;
451,440✔
5914
  int32_t type = pInputCol->info.type;
451,440✔
5915
  int32_t startOffset = pCtx->offset;
451,440✔
5916
  for (int32_t i = pInput->startRowIndex; i < pInput->numOfRows + pInput->startRowIndex; i += 1) {
130,606,197✔
5917
    if (pInfo->isPrevTsSet == true && tsList[i] == pInfo->prevTs) {
130,156,049✔
5918
      return TSDB_CODE_FUNC_DUP_TIMESTAMP;
800✔
5919
    } else {
5920
      pInfo->prevTs = tsList[i];
130,154,757✔
5921
    }
5922
    pInfo->isPrevTsSet = true;
130,154,265✔
5923

5924
    int32_t pos = startOffset + numOfElems;
130,154,265✔
5925
    if (colDataIsNull_f(pInputCol, i)) {
130,154,265✔
5926
      // colDataSetNULL(pOutput, i);
5927
      continue;
56,575,739✔
5928
    }
5929

5930
    char*  data = colDataGetData(pInputCol, i);
73,579,870✔
5931
    double v;
5932
    GET_TYPED_DATA(v, double, type, data, typeGetTypeModFromColInfo(&pInputCol->info));
73,580,230✔
5933

5934
    if (!pInfo->pointsMeet && (pInfo->pos < pInfo->numOfPoints - 1)) {
73,580,230✔
5935
      pInfo->points[pInfo->pos] = v;
9,657,174✔
5936
      pInfo->sum += v;
9,657,534✔
5937
    } else {
5938
      if (!pInfo->pointsMeet && (pInfo->pos == pInfo->numOfPoints - 1)) {
63,923,056✔
5939
        pInfo->sum += v;
83,027✔
5940
        pInfo->pointsMeet = true;
83,027✔
5941
      } else {
5942
        pInfo->sum = pInfo->sum + v - pInfo->points[pInfo->pos];
63,839,669✔
5943
      }
5944

5945
      pInfo->points[pInfo->pos] = v;
63,922,696✔
5946
      double result = pInfo->sum / pInfo->numOfPoints;
63,922,696✔
5947
      // check for overflow
5948
      if (isinf(result) || isnan(result)) {
63,922,696✔
UNCOV
5949
        colDataSetNULL(pOutput, pos);
×
5950
      } else {
5951
        code = colDataSetVal(pOutput, pos, (char*)&result, false);
63,922,696✔
5952
        if (TSDB_CODE_SUCCESS != code) {
63,922,696✔
UNCOV
5953
          return code;
×
5954
        }
5955
      }
5956

5957
      // handle selectivity
5958
      if (pCtx->subsidiaries.num > 0) {
63,922,696✔
5959
        code = appendSelectivityValue(pCtx, i, pos);
31,482✔
5960
        if (TSDB_CODE_SUCCESS != code) {
31,482✔
UNCOV
5961
          return code;
×
5962
        }
5963
      }
5964

5965
      numOfElems++;
63,922,696✔
5966
    }
5967

5968
    pInfo->pos++;
73,579,510✔
5969
    if (pInfo->pos == pInfo->numOfPoints) {
73,579,510✔
5970
      pInfo->pos = 0;
824,465✔
5971
    }
5972
  }
5973

5974
  pResInfo->numOfRes = numOfElems;
450,640✔
5975
  return TSDB_CODE_SUCCESS;
450,640✔
5976
}
5977

5978
static SSampleInfo* getSampleOutputInfo(SqlFunctionCtx* pCtx) {
3,965,022✔
5979
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
3,965,022✔
5980
  SSampleInfo*         pInfo = GET_ROWCELL_INTERBUF(pResInfo);
3,965,873✔
5981

5982
  pInfo->data = (char*)pInfo + sizeof(SSampleInfo);
3,965,377✔
5983
  pInfo->tuplePos = (STuplePos*)((char*)pInfo + sizeof(SSampleInfo) + pInfo->samples * pInfo->colBytes);
3,965,873✔
5984

5985
  return pInfo;
3,965,377✔
5986
}
5987

5988
bool getSampleFuncEnv(SFunctionNode* pFunc, SFuncExecEnv* pEnv) {
752,140✔
5989
  SColumnNode* pCol = (SColumnNode*)nodesListGetNode(pFunc->pParameterList, 0);
752,140✔
5990
  SValueNode*  pVal = (SValueNode*)nodesListGetNode(pFunc->pParameterList, 1);
752,636✔
5991
  int32_t      numOfSamples = pVal->datum.i;
751,313✔
5992
  pEnv->calcMemSize = sizeof(SSampleInfo) + numOfSamples * (pCol->node.resType.bytes + sizeof(STuplePos));
751,313✔
5993
  return true;
751,160✔
5994
}
5995

5996
int32_t sampleFunctionSetup(SqlFunctionCtx* pCtx, SResultRowEntryInfo* pResultInfo) {
1,648,574✔
5997
  if (pResultInfo->initialized) {
1,648,574✔
UNCOV
5998
    return TSDB_CODE_SUCCESS;
×
5999
  }
6000
  if (TSDB_CODE_SUCCESS != functionSetup(pCtx, pResultInfo)) {
1,648,574✔
UNCOV
6001
    return TSDB_CODE_FUNC_SETUP_ERROR;
×
6002
  }
6003

6004
  taosSeedRand(taosSafeRand());
1,648,090✔
6005

6006
  SSampleInfo* pInfo = GET_ROWCELL_INTERBUF(pResultInfo);
1,648,574✔
6007
  pInfo->samples = pCtx->param[1].param.i;
1,648,574✔
6008
  pInfo->totalPoints = 0;
1,648,574✔
6009
  pInfo->numSampled = 0;
1,648,574✔
6010
  pInfo->colType = pCtx->resDataInfo.type;
1,648,574✔
6011
  pInfo->colBytes = pCtx->resDataInfo.bytes;
1,648,574✔
6012
  pInfo->nullTuplePos.pageId = -1;
1,648,574✔
6013
  pInfo->nullTupleSaved = false;
1,648,574✔
6014
  pInfo->data = (char*)pInfo + sizeof(SSampleInfo);
1,648,574✔
6015
  pInfo->tuplePos = (STuplePos*)((char*)pInfo + sizeof(SSampleInfo) + pInfo->samples * pInfo->colBytes);
1,648,574✔
6016

6017
  return TSDB_CODE_SUCCESS;
1,648,574✔
6018
}
6019

6020
static void sampleAssignResult(SSampleInfo* pInfo, char* data, int32_t index) {
96,926,000✔
6021
  assignVal(pInfo->data + index * pInfo->colBytes, data, pInfo->colBytes, pInfo->colType);
96,926,000✔
6022
}
96,925,295✔
6023

6024
static int32_t doReservoirSample(SqlFunctionCtx* pCtx, SSampleInfo* pInfo, char* data, int32_t index) {
130,429,853✔
6025
  pInfo->totalPoints++;
130,429,853✔
6026
  if (pInfo->numSampled < pInfo->samples) {
130,431,712✔
6027
    sampleAssignResult(pInfo, data, pInfo->numSampled);
95,476,981✔
6028
    if (pCtx->subsidiaries.num > 0) {
95,466,905✔
6029
      int32_t code = saveTupleData(pCtx, index, pCtx->pSrcBlock, &pInfo->tuplePos[pInfo->numSampled]);
956,180✔
6030
      if (code != TSDB_CODE_SUCCESS) {
956,180✔
UNCOV
6031
        return code;
×
6032
      }
6033
    }
6034
    pInfo->numSampled++;
95,471,306✔
6035
  } else {
6036
    int32_t j = taosRand() % (pInfo->totalPoints);
34,954,872✔
6037
    if (j < pInfo->samples) {
34,954,072✔
6038
      sampleAssignResult(pInfo, data, j);
1,452,851✔
6039
      if (pCtx->subsidiaries.num > 0) {
1,452,851✔
6040
        int32_t code = updateTupleData(pCtx, index, pCtx->pSrcBlock, &pInfo->tuplePos[j]);
312,925✔
6041
        if (code != TSDB_CODE_SUCCESS) {
311,770✔
UNCOV
6042
          return code;
×
6043
        }
6044
      }
6045
    }
6046
  }
6047

6048
  return TSDB_CODE_SUCCESS;
130,428,027✔
6049
}
6050

6051
int32_t sampleFunction(SqlFunctionCtx* pCtx) {
2,319,558✔
6052
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
2,319,558✔
6053
  SSampleInfo*         pInfo = getSampleOutputInfo(pCtx);
2,319,558✔
6054

6055
  SInputColumnInfoData* pInput = &pCtx->input;
2,319,558✔
6056

6057
  SColumnInfoData* pInputCol = pInput->pData[0];
2,319,558✔
6058
  for (int32_t i = pInput->startRowIndex; i < pInput->numOfRows + pInput->startRowIndex; i += 1) {
142,836,021✔
6059
    if (colDataIsNull_s(pInputCol, i)) {
280,990,992✔
6060
      continue;
10,092,256✔
6061
    }
6062

6063
    char*   data = colDataGetData(pInputCol, i);
130,430,963✔
6064
    int32_t code = doReservoirSample(pCtx, pInfo, data, i);
130,432,867✔
6065
    if (code != TSDB_CODE_SUCCESS) {
130,424,207✔
UNCOV
6066
      return code;
×
6067
    }
6068
  }
6069

6070
  if (pInfo->numSampled == 0 && pCtx->subsidiaries.num > 0 && !pInfo->nullTupleSaved) {
2,320,054✔
6071
    int32_t code = saveTupleData(pCtx, pInput->startRowIndex, pCtx->pSrcBlock, &pInfo->nullTuplePos);
1,665✔
6072
    if (code != TSDB_CODE_SUCCESS) {
1,665✔
UNCOV
6073
      return code;
×
6074
    }
6075
    pInfo->nullTupleSaved = true;
1,665✔
6076
  }
6077

6078
  SET_VAL(pResInfo, pInfo->numSampled, pInfo->numSampled);
2,320,054✔
6079
  return TSDB_CODE_SUCCESS;
2,320,054✔
6080
}
6081

6082
int32_t sampleFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
1,646,174✔
6083
  int32_t              code = TSDB_CODE_SUCCESS;
1,646,174✔
6084
  SResultRowEntryInfo* pEntryInfo = GET_RES_INFO(pCtx);
1,646,174✔
6085

6086
  SSampleInfo* pInfo = getSampleOutputInfo(pCtx);
1,646,174✔
6087
  pEntryInfo->complete = true;
1,645,819✔
6088

6089
  int32_t          slotId = pCtx->pExpr->base.resSchema.slotId;
1,645,819✔
6090
  SColumnInfoData* pCol = taosArrayGet(pBlock->pDataBlock, slotId);
1,646,174✔
6091
  if (NULL == pCol) {
1,646,174✔
UNCOV
6092
    return TSDB_CODE_OUT_OF_RANGE;
×
6093
  }
6094

6095
  int32_t currentRow = pBlock->info.rows;
1,646,174✔
6096
  if (pInfo->numSampled == 0) {
1,646,174✔
6097
    colDataSetNULL(pCol, currentRow);
79,154✔
6098
    code = setSelectivityValue(pCtx, pBlock, &pInfo->nullTuplePos, currentRow);
79,154✔
6099
    return code;
79,154✔
6100
  }
6101
  for (int32_t i = 0; i < pInfo->numSampled; ++i) {
97,033,298✔
6102
    code = colDataSetVal(pCol, currentRow + i, pInfo->data + i * pInfo->colBytes, false);
95,467,484✔
6103
    if (TSDB_CODE_SUCCESS != code) {
95,466,137✔
UNCOV
6104
      return code;
×
6105
    }
6106
    code = setSelectivityValue(pCtx, pBlock, &pInfo->tuplePos[i], currentRow + i);
95,466,137✔
6107
    if (TSDB_CODE_SUCCESS != code) {
95,466,278✔
UNCOV
6108
      return code;
×
6109
    }
6110
  }
6111

6112
  return code;
1,567,020✔
6113
}
6114

UNCOV
6115
bool getTailFuncEnv(SFunctionNode* pFunc, SFuncExecEnv* pEnv) {
×
6116
#if 0
6117
  SColumnNode* pCol = (SColumnNode*)nodesListGetNode(pFunc->pParameterList, 0);
6118
  SValueNode*  pVal = (SValueNode*)nodesListGetNode(pFunc->pParameterList, 1);
6119
  int32_t      numOfPoints = pVal->datum.i;
6120
  pEnv->calcMemSize = sizeof(STailInfo) + numOfPoints * (POINTER_BYTES + sizeof(STailItem) + pCol->node.resType.bytes);
6121
#endif
UNCOV
6122
  return true;
×
6123
}
6124

UNCOV
6125
int32_t tailFunctionSetup(SqlFunctionCtx* pCtx, SResultRowEntryInfo* pResultInfo) {
×
6126
#if 0
6127
  if (!functionSetup(pCtx, pResultInfo)) {
6128
    return false;
6129
  }
6130

6131
  STailInfo* pInfo = GET_ROWCELL_INTERBUF(pResultInfo);
6132
  pInfo->numAdded = 0;
6133
  pInfo->numOfPoints = pCtx->param[1].param.i;
6134
  if (pCtx->numOfParams == 4) {
6135
    pInfo->offset = pCtx->param[2].param.i;
6136
  } else {
6137
    pInfo->offset = 0;
6138
  }
6139
  pInfo->colType = pCtx->resDataInfo.type;
6140
  pInfo->colBytes = pCtx->resDataInfo.bytes;
6141
  if ((pInfo->numOfPoints < 1 || pInfo->numOfPoints > TAIL_MAX_POINTS_NUM) ||
6142
      (pInfo->numOfPoints < 0 || pInfo->numOfPoints > TAIL_MAX_OFFSET)) {
6143
    return false;
6144
  }
6145

6146
  pInfo->pItems = (STailItem**)((char*)pInfo + sizeof(STailInfo));
6147
  char* pItem = (char*)pInfo->pItems + pInfo->numOfPoints * POINTER_BYTES;
6148

6149
  size_t unitSize = sizeof(STailItem) + pInfo->colBytes;
6150
  for (int32_t i = 0; i < pInfo->numOfPoints; ++i) {
6151
    pInfo->pItems[i] = (STailItem*)(pItem + i * unitSize);
6152
    pInfo->pItems[i]->isNull = false;
6153
  }
6154
#endif
UNCOV
6155
  return TSDB_CODE_SUCCESS;
×
6156
}
6157

6158
static void tailAssignResult(STailItem* pItem, char* data, int32_t colBytes, TSKEY ts, bool isNull) {
×
6159
#if 0
6160
  pItem->timestamp = ts;
6161
  if (isNull) {
6162
    pItem->isNull = true;
6163
  } else {
6164
    pItem->isNull = false;
6165
    memcpy(pItem->data, data, colBytes);
6166
  }
6167
#endif
UNCOV
6168
}
×
6169

6170
#if 0
6171
static int32_t tailCompFn(const void* p1, const void* p2, const void* param) {
6172
  STailItem* d1 = *(STailItem**)p1;
6173
  STailItem* d2 = *(STailItem**)p2;
6174
  return compareInt64Val(&d1->timestamp, &d2->timestamp);
6175
}
6176

6177
static void doTailAdd(STailInfo* pInfo, char* data, TSKEY ts, bool isNull) {
6178
  STailItem** pList = pInfo->pItems;
6179
  if (pInfo->numAdded < pInfo->numOfPoints) {
6180
    tailAssignResult(pList[pInfo->numAdded], data, pInfo->colBytes, ts, isNull);
6181
    taosheapsort((void*)pList, sizeof(STailItem**), pInfo->numAdded + 1, NULL, tailCompFn, 0);
6182
    pInfo->numAdded++;
6183
  } else if (pList[0]->timestamp < ts) {
6184
    tailAssignResult(pList[0], data, pInfo->colBytes, ts, isNull);
6185
    taosheapadjust((void*)pList, sizeof(STailItem**), 0, pInfo->numOfPoints - 1, NULL, tailCompFn, NULL, 0);
6186
  }
6187
}
6188
#endif
6189

UNCOV
6190
int32_t tailFunction(SqlFunctionCtx* pCtx) {
×
6191
#if 0
6192
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
6193
  STailInfo*           pInfo = GET_ROWCELL_INTERBUF(pResInfo);
6194

6195
  SInputColumnInfoData* pInput = &pCtx->input;
6196
  TSKEY*                tsList = (int64_t*)pInput->pPTS->pData;
6197

6198
  SColumnInfoData* pInputCol = pInput->pData[0];
6199
  SColumnInfoData* pOutput = (SColumnInfoData*)pCtx->pOutput;
6200

6201
  int32_t startOffset = pCtx->offset;
6202
  if (pInfo->offset >= pInput->numOfRows) {
6203
    return 0;
6204
  } else {
6205
    pInfo->numOfPoints = TMIN(pInfo->numOfPoints, pInput->numOfRows - pInfo->offset);
6206
  }
6207
  for (int32_t i = pInput->startRowIndex; i < pInput->numOfRows + pInput->startRowIndex - pInfo->offset; i += 1) {
6208
    char* data = colDataGetData(pInputCol, i);
6209
    doTailAdd(pInfo, data, tsList[i], colDataIsNull_s(pInputCol, i));
6210
  }
6211

6212
  taosqsort(pInfo->pItems, pInfo->numOfPoints, POINTER_BYTES, NULL, tailCompFn);
6213

6214
  for (int32_t i = 0; i < pInfo->numOfPoints; ++i) {
6215
    int32_t    pos = startOffset + i;
6216
    STailItem* pItem = pInfo->pItems[i];
6217
    if (pItem->isNull) {
6218
      colDataSetNULL(pOutput, pos);
6219
    } else {
6220
      colDataSetVal(pOutput, pos, pItem->data, false);
6221
    }
6222
  }
6223

6224
  return pInfo->numOfPoints;
6225
#endif
UNCOV
6226
  return 0;
×
6227
}
6228

UNCOV
6229
int32_t tailFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
×
6230
#if 0
6231
  SResultRowEntryInfo* pEntryInfo = GET_RES_INFO(pCtx);
6232
  STailInfo*           pInfo = GET_ROWCELL_INTERBUF(pEntryInfo);
6233
  pEntryInfo->complete = true;
6234

6235
  int32_t type = pCtx->input.pData[0]->info.type;
6236
  int32_t slotId = pCtx->pExpr->base.resSchema.slotId;
6237

6238
  SColumnInfoData* pCol = taosArrayGet(pBlock->pDataBlock, slotId);
6239

6240
  // todo assign the tag value and the corresponding row data
6241
  int32_t currentRow = pBlock->info.rows;
6242
  for (int32_t i = 0; i < pEntryInfo->numOfRes; ++i) {
6243
    STailItem* pItem = pInfo->pItems[i];
6244
    colDataSetVal(pCol, currentRow, pItem->data, false);
6245
    currentRow += 1;
6246
  }
6247

6248
  return pEntryInfo->numOfRes;
6249
#endif
UNCOV
6250
  return 0;
×
6251
}
6252

UNCOV
6253
bool getUniqueFuncEnv(SFunctionNode* pFunc, SFuncExecEnv* pEnv) {
×
6254
#if 0
6255
  pEnv->calcMemSize = sizeof(SUniqueInfo) + UNIQUE_MAX_RESULT_SIZE;
6256
#endif
UNCOV
6257
  return true;
×
6258
}
6259

UNCOV
6260
int32_t uniqueFunctionSetup(SqlFunctionCtx* pCtx, SResultRowEntryInfo* pResInfo) {
×
6261
#if 0
6262
  if (!functionSetup(pCtx, pResInfo)) {
6263
    return false;
6264
  }
6265

6266
  SUniqueInfo* pInfo = GET_ROWCELL_INTERBUF(pResInfo);
6267
  pInfo->numOfPoints = 0;
6268
  pInfo->colType = pCtx->resDataInfo.type;
6269
  pInfo->colBytes = pCtx->resDataInfo.bytes;
6270
  if (pInfo->pHash != NULL) {
6271
    taosHashClear(pInfo->pHash);
6272
  } else {
6273
    pInfo->pHash = taosHashInit(64, taosGetDefaultHashFunction(TSDB_DATA_TYPE_BINARY), true, HASH_NO_LOCK);
6274
  }
6275
#endif
UNCOV
6276
  return TSDB_CODE_SUCCESS;
×
6277
}
6278

6279
#if 0
6280
static void doUniqueAdd(SUniqueInfo* pInfo, char* data, TSKEY ts, bool isNull) {
6281
  // handle null elements
6282
  if (isNull == true) {
6283
    int32_t      size = sizeof(SUniqueItem) + pInfo->colBytes;
6284
    SUniqueItem* pItem = (SUniqueItem*)(pInfo->pItems + pInfo->numOfPoints * size);
6285
    if (pInfo->hasNull == false && pItem->isNull == false) {
6286
      pItem->timestamp = ts;
6287
      pItem->isNull = true;
6288
      pInfo->numOfPoints++;
6289
      pInfo->hasNull = true;
6290
    } else if (pItem->timestamp > ts && pItem->isNull == true) {
6291
      pItem->timestamp = ts;
6292
    }
6293
    return;
6294
  }
6295

6296
  int32_t      hashKeyBytes = IS_VAR_DATA_TYPE(pInfo->colType) ? varDataTLen(data) : pInfo->colBytes;
6297
  SUniqueItem* pHashItem = taosHashGet(pInfo->pHash, data, hashKeyBytes);
6298
  if (pHashItem == NULL) {
6299
    int32_t      size = sizeof(SUniqueItem) + pInfo->colBytes;
6300
    SUniqueItem* pItem = (SUniqueItem*)(pInfo->pItems + pInfo->numOfPoints * size);
6301
    pItem->timestamp = ts;
6302
    memcpy(pItem->data, data, pInfo->colBytes);
6303

6304
    taosHashPut(pInfo->pHash, data, hashKeyBytes, (char*)pItem, sizeof(SUniqueItem*));
6305
    pInfo->numOfPoints++;
6306
  } else if (pHashItem->timestamp > ts) {
6307
    pHashItem->timestamp = ts;
6308
  }
6309
}
6310
#endif
6311

UNCOV
6312
int32_t uniqueFunction(SqlFunctionCtx* pCtx) {
×
6313
#if 0
6314
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
6315
  SUniqueInfo*         pInfo = GET_ROWCELL_INTERBUF(pResInfo);
6316

6317
  SInputColumnInfoData* pInput = &pCtx->input;
6318
  TSKEY*                tsList = (int64_t*)pInput->pPTS->pData;
6319

6320
  SColumnInfoData* pInputCol = pInput->pData[0];
6321
  SColumnInfoData* pTsOutput = pCtx->pTsOutput;
6322
  SColumnInfoData* pOutput = (SColumnInfoData*)pCtx->pOutput;
6323

6324
  int32_t startOffset = pCtx->offset;
6325
  for (int32_t i = pInput->startRowIndex; i < pInput->numOfRows + pInput->startRowIndex; ++i) {
6326
    char* data = colDataGetData(pInputCol, i);
6327
    doUniqueAdd(pInfo, data, tsList[i], colDataIsNull_s(pInputCol, i));
6328

6329
    if (sizeof(SUniqueInfo) + pInfo->numOfPoints * (sizeof(SUniqueItem) + pInfo->colBytes) >= UNIQUE_MAX_RESULT_SIZE) {
6330
      taosHashCleanup(pInfo->pHash);
6331
      return 0;
6332
    }
6333
  }
6334

6335
  for (int32_t i = 0; i < pInfo->numOfPoints; ++i) {
6336
    SUniqueItem* pItem = (SUniqueItem*)(pInfo->pItems + i * (sizeof(SUniqueItem) + pInfo->colBytes));
6337
    if (pItem->isNull == true) {
6338
      colDataSetNULL(pOutput, i);
6339
    } else {
6340
      colDataSetVal(pOutput, i, pItem->data, false);
6341
    }
6342
    if (pTsOutput != NULL) {
6343
      colDataSetInt64(pTsOutput, i, &pItem->timestamp);
6344
    }
6345
  }
6346

6347
  return pInfo->numOfPoints;
6348
#endif
6349
  return 0;
×
6350
}
6351

6352
bool getModeFuncEnv(SFunctionNode* pFunc, SFuncExecEnv* pEnv) {
1,213,496✔
6353
  pEnv->calcMemSize = sizeof(SModeInfo);
1,213,496✔
6354
  return true;
1,213,992✔
6355
}
6356

6357
int32_t modeFunctionSetup(SqlFunctionCtx* pCtx, SResultRowEntryInfo* pResInfo) {
2,001,351✔
6358
  if (pResInfo->initialized) {
2,001,351✔
UNCOV
6359
    return TSDB_CODE_SUCCESS;
×
6360
  }
6361
  if (TSDB_CODE_SUCCESS != functionSetup(pCtx, pResInfo)) {
2,001,351✔
UNCOV
6362
    return TSDB_CODE_FUNC_SETUP_ERROR;
×
6363
  }
6364

6365
  SModeInfo* pInfo = GET_ROWCELL_INTERBUF(pResInfo);
2,001,797✔
6366
  pInfo->colType = pCtx->resDataInfo.type;
2,001,351✔
6367
  pInfo->colBytes = pCtx->resDataInfo.bytes;
2,001,797✔
6368
  if (pInfo->pHash != NULL) {
2,001,351✔
UNCOV
6369
    taosHashClear(pInfo->pHash);
×
6370
  } else {
6371
    pInfo->pHash = taosHashInit(64, taosGetDefaultHashFunction(TSDB_DATA_TYPE_BINARY), true, HASH_NO_LOCK);
2,001,351✔
6372
    if (NULL == pInfo->pHash) {
2,001,797✔
UNCOV
6373
      return terrno;
×
6374
    }
6375
  }
6376
  pInfo->nullTupleSaved = false;
2,001,797✔
6377
  pInfo->nullTuplePos.pageId = -1;
2,001,797✔
6378

6379
  pInfo->buf = taosMemoryMalloc(pInfo->colBytes);
2,001,797✔
6380
  if (NULL == pInfo->buf) {
2,001,797✔
UNCOV
6381
    taosHashCleanup(pInfo->pHash);
×
UNCOV
6382
    pInfo->pHash = NULL;
×
UNCOV
6383
    return terrno;
×
6384
  }
6385
  pCtx->needCleanup = true;
2,001,797✔
6386
  return TSDB_CODE_SUCCESS;
2,001,797✔
6387
}
6388

6389
static void modeFunctionCleanup(SModeInfo* pInfo) {
3,150,704✔
6390
  taosHashCleanup(pInfo->pHash);
3,150,704✔
6391
  pInfo->pHash = NULL;
3,150,704✔
6392
  taosMemoryFreeClear(pInfo->buf);
3,150,704✔
6393
}
3,150,208✔
6394

6395
void modeFunctionCleanupExt(SqlFunctionCtx* pCtx) {
1,214,347✔
6396
  if (pCtx == NULL || GET_RES_INFO(pCtx) == NULL || GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx)) == NULL) {
1,214,347✔
6397
    return;
64,240✔
6398
  }
6399
  modeFunctionCleanup(GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx)));
1,149,623✔
6400
}
6401

6402
static int32_t saveModeTupleData(SqlFunctionCtx* pCtx, char* data, SModeInfo* pInfo, STuplePos* pPos) {
2,147,483,647✔
6403
  if (IS_VAR_DATA_TYPE(pInfo->colType)) {
2,147,483,647✔
6404
    if (pInfo->colType == TSDB_DATA_TYPE_JSON) {
23,770,614✔
6405
      (void)memcpy(pInfo->buf, data, getJsonValueLen(data));
255,420✔
6406
    } else if (IS_STR_DATA_BLOB(pInfo->colType)) {
23,517,014✔
UNCOV
6407
      (void)memcpy(pInfo->buf, data, blobDataTLen(data));
×
6408
    } else {
6409
      (void)memcpy(pInfo->buf, data, varDataTLen(data));
23,517,014✔
6410
    }
6411
  } else {
6412
    (void)memcpy(pInfo->buf, data, pInfo->colBytes);
2,147,483,647✔
6413
  }
6414

6415
  return doSaveTupleData(&pCtx->saveHandle, pInfo->buf, pInfo->colBytes, NULL, pPos, pCtx->pStore);
2,147,483,647✔
6416
}
6417

6418
static int32_t doModeAdd(SModeInfo* pInfo, int32_t rowIndex, SqlFunctionCtx* pCtx, char* data) {
2,147,483,647✔
6419
  int32_t code = TSDB_CODE_SUCCESS;
2,147,483,647✔
6420
  int32_t hashKeyBytes;
6421
  if (IS_VAR_DATA_TYPE(pInfo->colType)) {
2,147,483,647✔
6422
    hashKeyBytes = calcStrBytesByType(pInfo->colType, data);
2,147,483,647✔
6423
  } else {
6424
    hashKeyBytes = pInfo->colBytes;
2,147,483,647✔
6425
  }
6426

6427
  SModeItem* pHashItem = (SModeItem*)taosHashGet(pInfo->pHash, data, hashKeyBytes);
2,147,483,647✔
6428
  if (pHashItem == NULL) {
2,147,483,647✔
6429
    int32_t   size = sizeof(SModeItem);
2,147,483,647✔
6430
    SModeItem item = {0};
2,147,483,647✔
6431

6432
    item.count += 1;
2,147,483,647✔
6433
    code = saveModeTupleData(pCtx, data, pInfo, &item.dataPos);
2,147,483,647✔
6434
    if (code != TSDB_CODE_SUCCESS) {
2,147,483,647✔
UNCOV
6435
      return code;
×
6436
    }
6437

6438
    if (pCtx->subsidiaries.num > 0) {
2,147,483,647✔
6439
      code = saveTupleData(pCtx, rowIndex, pCtx->pSrcBlock, &item.tuplePos);
246,506✔
6440
      if (code != TSDB_CODE_SUCCESS) {
246,506✔
UNCOV
6441
        return code;
×
6442
      }
6443
    }
6444

6445
    code = taosHashPut(pInfo->pHash, data, hashKeyBytes, &item, sizeof(SModeItem));
2,147,483,647✔
6446
    if (code != TSDB_CODE_SUCCESS) {
2,147,483,647✔
UNCOV
6447
      return code;
×
6448
    }
6449
  } else {
6450
    pHashItem->count += 1;
2,147,483,647✔
6451
    if (pCtx->subsidiaries.num > 0) {
2,147,483,647✔
6452
      code = updateTupleData(pCtx, rowIndex, pCtx->pSrcBlock, &pHashItem->tuplePos);
3,098,934✔
6453
      if (code != TSDB_CODE_SUCCESS) {
3,098,934✔
UNCOV
6454
        return code;
×
6455
      }
6456
    }
6457
  }
6458

6459
  return code;
2,147,483,647✔
6460
}
6461

6462
int32_t modeFunction(SqlFunctionCtx* pCtx) {
2,147,483,647✔
6463
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
2,147,483,647✔
6464
  SModeInfo*           pInfo = GET_ROWCELL_INTERBUF(pResInfo);
2,147,483,647✔
6465

6466
  SInputColumnInfoData* pInput = &pCtx->input;
2,147,483,647✔
6467

6468
  SColumnInfoData* pInputCol = pInput->pData[0];
2,147,483,647✔
6469
  SColumnInfoData* pOutput = (SColumnInfoData*)pCtx->pOutput;
2,147,483,647✔
6470

6471
  int32_t numOfElems = 0;
2,147,483,647✔
6472
  int32_t startOffset = pCtx->offset;
2,147,483,647✔
6473
  for (int32_t i = pInput->startRowIndex; i < pInput->numOfRows + pInput->startRowIndex; ++i) {
2,147,483,647✔
6474
    if (colDataIsNull_s(pInputCol, i)) {
2,147,483,647✔
6475
      continue;
2,147,483,647✔
6476
    }
6477
    numOfElems++;
2,147,483,647✔
6478

6479
    char*   data = colDataGetData(pInputCol, i);
2,147,483,647✔
6480
    int32_t code = doModeAdd(pInfo, i, pCtx, data);
2,147,483,647✔
6481
    if (code != TSDB_CODE_SUCCESS) {
2,147,483,647✔
6482
      modeFunctionCleanup(pInfo);
12,619✔
UNCOV
6483
      return code;
×
6484
    }
6485
  }
6486

6487
  if (numOfElems == 0 && pCtx->subsidiaries.num > 0 && !pInfo->nullTupleSaved) {
2,147,483,647✔
6488
    int32_t code = saveTupleData(pCtx, pInput->startRowIndex, pCtx->pSrcBlock, &pInfo->nullTuplePos);
4,300✔
6489
    if (code != TSDB_CODE_SUCCESS) {
4,300✔
UNCOV
6490
      modeFunctionCleanup(pInfo);
×
UNCOV
6491
      return code;
×
6492
    }
6493
    pInfo->nullTupleSaved = true;
4,300✔
6494
  }
6495

6496
  SET_VAL(pResInfo, numOfElems, 1);
2,147,483,647✔
6497

6498
  return TSDB_CODE_SUCCESS;
2,147,483,647✔
6499
}
6500

6501
int32_t modeFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
2,000,597✔
6502
  int32_t              code = TSDB_CODE_SUCCESS;
2,000,597✔
6503
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
2,000,597✔
6504
  SModeInfo*           pInfo = GET_ROWCELL_INTERBUF(pResInfo);
1,999,605✔
6505
  int32_t              slotId = pCtx->pExpr->base.resSchema.slotId;
2,000,597✔
6506
  SColumnInfoData*     pCol = taosArrayGet(pBlock->pDataBlock, slotId);
2,000,101✔
6507
  int32_t              currentRow = pBlock->info.rows;
2,000,101✔
6508
  if (NULL == pCol) {
1,999,605✔
6509
    modeFunctionCleanup(pInfo);
×
6510
    return TSDB_CODE_OUT_OF_RANGE;
×
6511
  }
6512

6513
  STuplePos resDataPos, resTuplePos;
1,999,605✔
6514
  int32_t   maxCount = 0;
2,000,101✔
6515

6516
  void* pIter = taosHashIterate(pInfo->pHash, NULL);
2,000,101✔
6517
  while (pIter != NULL) {
2,147,483,647✔
6518
    SModeItem* pItem = (SModeItem*)pIter;
2,147,483,647✔
6519
    if (pItem->count >= maxCount) {
2,147,483,647✔
6520
      maxCount = pItem->count;
1,903,602,020✔
6521
      resDataPos = pItem->dataPos;
1,903,602,020✔
6522
      resTuplePos = pItem->tuplePos;
1,903,602,020✔
6523
    }
6524

6525
    pIter = taosHashIterate(pInfo->pHash, pIter);
2,147,483,647✔
6526
  }
6527

6528
  if (maxCount != 0) {
2,000,597✔
6529
    char* pData = NULL;
1,472,433✔
6530
    code = loadTupleData(pCtx, &resDataPos, &pData);
1,472,433✔
6531
    if (pData == NULL || TSDB_CODE_SUCCESS != code) {
1,472,433✔
UNCOV
6532
      code = terrno = TSDB_CODE_NOT_FOUND;
×
6533
      qError("Load tuple data failed since %s, groupId:%" PRIu64 ", ts:%" PRId64, terrstr(),
×
6534
             resDataPos.streamTupleKey.groupId, resDataPos.streamTupleKey.ts);
UNCOV
6535
      modeFunctionCleanup(pInfo);
×
UNCOV
6536
      return code;
×
6537
    }
6538

6539
    code = colDataSetVal(pCol, currentRow, pData, false);
1,472,433✔
6540
    if (TSDB_CODE_SUCCESS != code) {
1,472,433✔
UNCOV
6541
      modeFunctionCleanup(pInfo);
×
UNCOV
6542
      return code;
×
6543
    }
6544
    code = setSelectivityValue(pCtx, pBlock, &resTuplePos, currentRow);
1,472,433✔
6545
  } else {
6546
    colDataSetNULL(pCol, currentRow);
528,164✔
6547
    code = setSelectivityValue(pCtx, pBlock, &pInfo->nullTuplePos, currentRow);
528,164✔
6548
  }
6549

6550
  modeFunctionCleanup(pInfo);
2,000,597✔
6551

6552
  return code;
2,000,101✔
6553
}
6554

6555
bool getTwaFuncEnv(struct SFunctionNode* pFunc, SFuncExecEnv* pEnv) {
290,411✔
6556
  pEnv->calcMemSize = sizeof(STwaInfo);
290,411✔
6557
  return true;
290,411✔
6558
}
6559

6560
int32_t twaFunctionSetup(SqlFunctionCtx* pCtx, SResultRowEntryInfo* pResultInfo) {
7,200,895✔
6561
  if (pResultInfo->initialized) {
7,200,895✔
UNCOV
6562
    return TSDB_CODE_SUCCESS;
×
6563
  }
6564
  if (TSDB_CODE_SUCCESS != functionSetup(pCtx, pResultInfo)) {
7,200,895✔
UNCOV
6565
    return TSDB_CODE_FUNC_SETUP_ERROR;
×
6566
  }
6567

6568
  STwaInfo* pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
7,200,895✔
6569
  pInfo->numOfElems = 0;
7,200,895✔
6570
  pInfo->p.key = INT64_MIN;
7,200,895✔
6571
  pInfo->win = TSWINDOW_INITIALIZER;
7,200,895✔
6572
  return TSDB_CODE_SUCCESS;
7,200,895✔
6573
}
6574

6575
static double twa_get_area(SPoint1 s, SPoint1 e) {
173,785,222✔
6576
  if (e.key == INT64_MAX || s.key == INT64_MIN) {
173,785,222✔
UNCOV
6577
    return 0;
×
6578
  }
6579

6580
  if ((s.val >= 0 && e.val >= 0) || (s.val <= 0 && e.val <= 0)) {
173,795,300✔
6581
    return (s.val + e.val) * (e.key - s.key) / 2;
158,849,460✔
6582
  }
6583

6584
  double x = (s.key * e.val - e.key * s.val) / (e.val - s.val);
14,945,840✔
6585
  double val = (s.val * (x - s.key) + e.val * (e.key - x)) / 2;
14,945,840✔
6586
  return val;
14,945,840✔
6587
}
6588

6589
int32_t twaFunction(SqlFunctionCtx* pCtx) {
7,341,304✔
6590
  int32_t               code = TSDB_CODE_SUCCESS;
7,341,304✔
6591
  SInputColumnInfoData* pInput = &pCtx->input;
7,341,304✔
6592
  SColumnInfoData*      pInputCol = pInput->pData[0];
7,341,304✔
6593

6594
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
7,340,889✔
6595
  STwaInfo*            pInfo = GET_ROWCELL_INTERBUF(pResInfo);
7,340,889✔
6596
  SPoint1*             last = &pInfo->p;
7,340,474✔
6597

6598
  if (IS_NULL_TYPE(pInputCol->info.type)) {
7,341,304✔
UNCOV
6599
    pInfo->numOfElems = 0;
×
6600
    goto _twa_over;
×
6601
  }
6602

6603
  funcInputUpdate(pCtx);
7,340,889✔
6604
  SFuncInputRow row = {0};
7,341,304✔
6605
  bool          result = false;
7,341,304✔
6606
  if (pCtx->start.key != INT64_MIN && last->key == INT64_MIN) {
7,341,304✔
6607
    while (1) {
6608
      code = funcInputGetNextRow(pCtx, &row, &result);
5,021,456✔
6609
      if (TSDB_CODE_SUCCESS != code) {
5,021,456✔
UNCOV
6610
        return code;
×
6611
      }
6612
      if (!result) {
5,021,456✔
6613
        break;
712✔
6614
      }
6615
      if (row.isDataNull) {
5,020,744✔
6616
        continue;
712✔
6617
      }
6618

6619
      last->key = row.ts;
5,020,032✔
6620

6621
      GET_TYPED_DATA(last->val, double, pInputCol->info.type, row.pData, typeGetTypeModFromColInfo(&pInputCol->info));
5,020,032✔
6622

6623
      pInfo->dOutput += twa_get_area(pCtx->start, *last);
5,020,032✔
6624
      pInfo->win.skey = pCtx->start.key;
5,020,032✔
6625
      pInfo->numOfElems++;
5,020,032✔
6626
      break;
5,020,032✔
6627
    }
6628
  } else if (pInfo->p.key == INT64_MIN) {
2,320,145✔
6629
    while (1) {
6630
      code = funcInputGetNextRow(pCtx, &row, &result);
10,391,901✔
6631
      if (TSDB_CODE_SUCCESS != code) {
10,392,316✔
UNCOV
6632
        return code;
×
6633
      }
6634
      if (!result) {
10,392,316✔
6635
        break;
706,214✔
6636
      }
6637
      if (row.isDataNull) {
9,686,102✔
6638
        continue;
8,168,638✔
6639
      }
6640

6641
      last->key = row.ts;
1,517,464✔
6642

6643
      GET_TYPED_DATA(last->val, double, pInputCol->info.type, row.pData, typeGetTypeModFromColInfo(&pInputCol->info));
1,517,049✔
6644

6645
      pInfo->win.skey = last->key;
1,517,464✔
6646
      pInfo->numOfElems++;
1,517,464✔
6647
      break;
1,517,464✔
6648
    }
6649
  }
6650

6651
  SPoint1 st = {0};
7,341,304✔
6652

6653
  // calculate the value of
6654
  while (1) {
6655
    code = funcInputGetNextRow(pCtx, &row, &result);
171,122,240✔
6656
    if (TSDB_CODE_SUCCESS != code) {
171,157,515✔
UNCOV
6657
      return code;
×
6658
    }
6659
    if (!result) {
171,157,515✔
6660
      break;
7,341,304✔
6661
    }
6662
    if (row.isDataNull) {
163,816,211✔
6663
      continue;
52,290✔
6664
    }
6665
    pInfo->numOfElems++;
163,763,921✔
6666
    switch (pInputCol->info.type) {
163,762,676✔
6667
      case TSDB_DATA_TYPE_TINYINT: {
12,611,591✔
6668
        INIT_INTP_POINT(st, row.ts, *(int8_t*)row.pData);
12,611,591✔
6669
        break;
12,611,591✔
6670
      }
6671
      case TSDB_DATA_TYPE_SMALLINT: {
12,448,909✔
6672
        INIT_INTP_POINT(st, row.ts, *(int16_t*)row.pData);
12,448,909✔
6673
        break;
12,428,574✔
6674
      }
6675
      case TSDB_DATA_TYPE_INT: {
68,039,266✔
6676
        INIT_INTP_POINT(st, row.ts, *(int32_t*)row.pData);
68,039,266✔
6677
        break;
68,039,266✔
6678
      }
6679
      case TSDB_DATA_TYPE_BIGINT: {
13,917,320✔
6680
        INIT_INTP_POINT(st, row.ts, *(int64_t*)row.pData);
13,917,320✔
6681
        break;
13,916,905✔
6682
      }
6683
      case TSDB_DATA_TYPE_FLOAT: {
10,390,229✔
6684
        INIT_INTP_POINT(st, row.ts, *(float_t*)row.pData);
10,390,229✔
6685
        break;
10,390,229✔
6686
      }
6687
      case TSDB_DATA_TYPE_DOUBLE: {
13,553,204✔
6688
        INIT_INTP_POINT(st, row.ts, *(double*)row.pData);
13,553,204✔
6689
        break;
13,553,204✔
6690
      }
6691
      case TSDB_DATA_TYPE_UTINYINT: {
8,387,242✔
6692
        INIT_INTP_POINT(st, row.ts, *(uint8_t*)row.pData);
8,387,242✔
6693
        break;
8,387,657✔
6694
      }
6695
      case TSDB_DATA_TYPE_USMALLINT: {
8,386,412✔
6696
        INIT_INTP_POINT(st, row.ts, *(uint16_t*)row.pData);
8,386,412✔
6697
        break;
8,386,412✔
6698
      }
6699
      case TSDB_DATA_TYPE_UINT: {
8,432,779✔
6700
        INIT_INTP_POINT(st, row.ts, *(uint32_t*)row.pData);
8,432,779✔
6701
        break;
8,432,779✔
6702
      }
6703
      case TSDB_DATA_TYPE_UBIGINT: {
7,591,989✔
6704
        INIT_INTP_POINT(st, row.ts, *(uint64_t*)row.pData);
7,591,989✔
6705
        break;
7,591,989✔
6706
      }
UNCOV
6707
      default: {
×
UNCOV
6708
        return TSDB_CODE_FUNC_FUNTION_PARA_TYPE;
×
6709
      }
6710
    }
6711
    if (pInfo->p.key == st.key) {
163,738,606✔
UNCOV
6712
      return TSDB_CODE_FUNC_DUP_TIMESTAMP;
×
6713
    }
6714

6715
    pInfo->dOutput += twa_get_area(pInfo->p, st);
163,756,866✔
6716
    pInfo->p = st;
163,727,401✔
6717
  }
6718

6719
  // the last interpolated time window value
6720
  if (pCtx->end.key != INT64_MIN) {
7,341,304✔
6721
    pInfo->dOutput += twa_get_area(pInfo->p, pCtx->end);
5,022,849✔
6722
    pInfo->p = pCtx->end;
5,022,849✔
6723
    pInfo->numOfElems += 1;
5,022,849✔
6724
  }
6725

6726
  pInfo->win.ekey = pInfo->p.key;
7,341,304✔
6727

6728
_twa_over:
7,341,304✔
6729
  SET_VAL(pResInfo, 1, 1);
7,341,304✔
6730
  return TSDB_CODE_SUCCESS;
7,341,304✔
6731
}
6732

6733
/*
6734
 * To copy the input to interResBuf to avoid the input buffer space be over writen
6735
 * by next input data. The TWA function only applies to each table, so no merge procedure
6736
 * is required, we simply copy to the resut ot interResBuffer.
6737
 */
6738
// void twa_function_copy(SQLFunctionCtx *pCtx) {
6739
//   SResultRowEntryInfo *pResInfo = GET_RES_INFO(pCtx);
6740
//
6741
//   memcpy(GET_ROWCELL_INTERBUF(pResInfo), pCtx->pInput, (size_t)pCtx->inputBytes);
6742
//   pResInfo->hasResult = ((STwaInfo *)pCtx->pInput)->hasResult;
6743
// }
6744

6745
int32_t twaFinalize(struct SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
7,200,895✔
6746
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
7,200,895✔
6747

6748
  STwaInfo* pInfo = (STwaInfo*)GET_ROWCELL_INTERBUF(pResInfo);
7,200,895✔
6749
  if (pInfo->numOfElems == 0) {
7,200,895✔
6750
    pResInfo->numOfRes = 0;
662,687✔
6751
  } else {
6752
    if (pInfo->win.ekey == pInfo->win.skey) {
6,538,208✔
6753
      pInfo->dTwaRes = pInfo->p.val;
678,220✔
6754
    } else if (pInfo->win.ekey == INT64_MAX || pInfo->win.skey == INT64_MIN) {  // no data in timewindow
5,859,988✔
6755
      pInfo->dTwaRes = 0;
712✔
6756
    } else {
6757
      pInfo->dTwaRes = pInfo->dOutput / (pInfo->win.ekey - pInfo->win.skey);
5,859,276✔
6758
    }
6759

6760
    pResInfo->numOfRes = 1;
6,538,208✔
6761
  }
6762

6763
  return functionFinalize(pCtx, pBlock);
7,200,895✔
6764
}
6765

6766
int32_t blockDistSetup(SqlFunctionCtx* pCtx, SResultRowEntryInfo* pResultInfo) {
2,741✔
6767
  if (pResultInfo->initialized) {
2,741✔
UNCOV
6768
    return TSDB_CODE_SUCCESS;
×
6769
  }
6770
  if (TSDB_CODE_SUCCESS != functionSetup(pCtx, pResultInfo)) {
2,741✔
UNCOV
6771
    return TSDB_CODE_FUNC_SETUP_ERROR;
×
6772
  }
6773

6774
  STableBlockDistInfo* pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
2,741✔
6775
  pInfo->minRows = INT32_MAX;
2,741✔
6776
  return TSDB_CODE_SUCCESS;
2,741✔
6777
}
6778

6779
int32_t blockDistFunction(SqlFunctionCtx* pCtx) {
5,246✔
6780
  const int32_t BLOCK_DIST_RESULT_ROWS = 25;
5,246✔
6781

6782
  SInputColumnInfoData* pInput = &pCtx->input;
5,246✔
6783
  SColumnInfoData*      pInputCol = pInput->pData[0];
5,246✔
6784
  SResultRowEntryInfo*  pResInfo = GET_RES_INFO(pCtx);
5,246✔
6785
  STableBlockDistInfo*  pDistInfo = GET_ROWCELL_INTERBUF(pResInfo);
5,246✔
6786

6787
  STableBlockDistInfo p1 = {0};
5,246✔
6788
  if (tDeserializeBlockDistInfo(varDataVal(pInputCol->pData), varDataLen(pInputCol->pData), &p1) < 0) {
5,246✔
UNCOV
6789
    qError("failed to deserialize block dist info");
×
UNCOV
6790
    return TSDB_CODE_FAILED;
×
6791
  }
6792

6793
  pDistInfo->numOfBlocks += p1.numOfBlocks;
5,246✔
6794
  pDistInfo->numOfTables += p1.numOfTables;
5,246✔
6795
  pDistInfo->numOfInmemRows += p1.numOfInmemRows;
5,246✔
6796
  pDistInfo->numOfSttRows += p1.numOfSttRows;
5,246✔
6797
  pDistInfo->totalSize += p1.totalSize;
5,246✔
6798
  pDistInfo->totalRows += p1.totalRows;
5,246✔
6799
  pDistInfo->numOfFiles += p1.numOfFiles;
5,246✔
6800

6801
  pDistInfo->defMinRows = p1.defMinRows;
5,246✔
6802
  pDistInfo->defMaxRows = p1.defMaxRows;
5,246✔
6803
  pDistInfo->rowSize = p1.rowSize;
5,246✔
6804

6805
  if (pDistInfo->minRows > p1.minRows) {
5,246✔
6806
    pDistInfo->minRows = p1.minRows;
1,239✔
6807
  }
6808
  if (pDistInfo->maxRows < p1.maxRows) {
5,246✔
6809
    pDistInfo->maxRows = p1.maxRows;
1,239✔
6810
  }
6811
  pDistInfo->numOfVgroups += (p1.numOfTables != 0 ? 1 : 0);
5,246✔
6812
  for (int32_t i = 0; i < tListLen(pDistInfo->blockRowsHisto); ++i) {
110,166✔
6813
    pDistInfo->blockRowsHisto[i] += p1.blockRowsHisto[i];
104,920✔
6814
  }
6815

6816
  pResInfo->numOfRes = BLOCK_DIST_RESULT_ROWS;  // default output rows
5,246✔
6817
  return TSDB_CODE_SUCCESS;
5,246✔
6818
}
6819

6820
int32_t tSerializeBlockDistInfo(void* buf, int32_t bufLen, const STableBlockDistInfo* pInfo) {
10,320✔
6821
  SEncoder encoder = {0};
10,320✔
6822
  int32_t  code = 0;
10,492✔
6823
  int32_t  lino;
6824
  int32_t  tlen;
6825
  tEncoderInit(&encoder, buf, bufLen);
10,492✔
6826

6827
  TAOS_CHECK_EXIT(tStartEncode(&encoder));
10,492✔
6828
  TAOS_CHECK_EXIT(tEncodeU32(&encoder, pInfo->rowSize));
20,984✔
6829

6830
  TAOS_CHECK_EXIT(tEncodeU16(&encoder, pInfo->numOfFiles));
20,812✔
6831
  TAOS_CHECK_EXIT(tEncodeU32(&encoder, pInfo->numOfBlocks));
20,640✔
6832
  TAOS_CHECK_EXIT(tEncodeU32(&encoder, pInfo->numOfTables));
20,812✔
6833

6834
  TAOS_CHECK_EXIT(tEncodeU64(&encoder, pInfo->totalSize));
20,984✔
6835
  TAOS_CHECK_EXIT(tEncodeU64(&encoder, pInfo->totalRows));
20,812✔
6836
  TAOS_CHECK_EXIT(tEncodeI32(&encoder, pInfo->maxRows));
20,812✔
6837
  TAOS_CHECK_EXIT(tEncodeI32(&encoder, pInfo->minRows));
20,812✔
6838
  TAOS_CHECK_EXIT(tEncodeI32(&encoder, pInfo->defMaxRows));
20,640✔
6839
  TAOS_CHECK_EXIT(tEncodeI32(&encoder, pInfo->defMinRows));
20,812✔
6840
  TAOS_CHECK_EXIT(tEncodeU32(&encoder, pInfo->numOfInmemRows));
20,812✔
6841
  TAOS_CHECK_EXIT(tEncodeU32(&encoder, pInfo->numOfSttRows));
20,812✔
6842
  TAOS_CHECK_EXIT(tEncodeU32(&encoder, pInfo->numOfVgroups));
20,984✔
6843

6844
  for (int32_t i = 0; i < tListLen(pInfo->blockRowsHisto); ++i) {
217,580✔
6845
    TAOS_CHECK_EXIT(tEncodeI32(&encoder, pInfo->blockRowsHisto[i]));
414,692✔
6846
  }
6847

6848
  tEndEncode(&encoder);
9,976✔
6849

6850
_exit:
10,492✔
6851
  if (code) {
10,492✔
UNCOV
6852
    tlen = code;
×
6853
  } else {
6854
    tlen = encoder.pos;
10,492✔
6855
  }
6856
  tEncoderClear(&encoder);
10,492✔
6857
  return tlen;
10,492✔
6858
}
6859

6860
int32_t tDeserializeBlockDistInfo(void* buf, int32_t bufLen, STableBlockDistInfo* pInfo) {
5,246✔
6861
  SDecoder decoder = {0};
5,246✔
6862
  int32_t  code = 0;
5,246✔
6863
  int32_t  lino;
6864
  tDecoderInit(&decoder, buf, bufLen);
5,246✔
6865

6866
  TAOS_CHECK_EXIT(tStartDecode(&decoder));
5,246✔
6867
  TAOS_CHECK_EXIT(tDecodeU32(&decoder, &pInfo->rowSize));
10,492✔
6868

6869
  TAOS_CHECK_EXIT(tDecodeU16(&decoder, &pInfo->numOfFiles));
10,492✔
6870
  TAOS_CHECK_EXIT(tDecodeU32(&decoder, &pInfo->numOfBlocks));
10,492✔
6871
  TAOS_CHECK_EXIT(tDecodeU32(&decoder, &pInfo->numOfTables));
10,492✔
6872

6873
  TAOS_CHECK_EXIT(tDecodeU64(&decoder, &pInfo->totalSize));
10,492✔
6874
  TAOS_CHECK_EXIT(tDecodeU64(&decoder, &pInfo->totalRows));
10,492✔
6875
  TAOS_CHECK_EXIT(tDecodeI32(&decoder, &pInfo->maxRows));
10,492✔
6876
  TAOS_CHECK_EXIT(tDecodeI32(&decoder, &pInfo->minRows));
10,492✔
6877
  TAOS_CHECK_EXIT(tDecodeI32(&decoder, &pInfo->defMaxRows));
10,492✔
6878
  TAOS_CHECK_EXIT(tDecodeI32(&decoder, &pInfo->defMinRows));
10,492✔
6879
  TAOS_CHECK_EXIT(tDecodeU32(&decoder, &pInfo->numOfInmemRows));
10,492✔
6880
  TAOS_CHECK_EXIT(tDecodeU32(&decoder, &pInfo->numOfSttRows));
10,492✔
6881
  TAOS_CHECK_EXIT(tDecodeU32(&decoder, &pInfo->numOfVgroups));
10,492✔
6882

6883
  for (int32_t i = 0; i < tListLen(pInfo->blockRowsHisto); ++i) {
110,166✔
6884
    TAOS_CHECK_EXIT(tDecodeI32(&decoder, &pInfo->blockRowsHisto[i]));
209,840✔
6885
  }
6886

6887
_exit:
5,246✔
6888
  tDecoderClear(&decoder);
5,246✔
6889
  return code;
5,246✔
6890
}
6891

6892
int32_t blockDistFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
2,741✔
6893
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
2,741✔
6894
  STableBlockDistInfo* pData = GET_ROWCELL_INTERBUF(pResInfo);
2,741✔
6895

6896
  SColumnInfoData* pColInfo = taosArrayGet(pBlock->pDataBlock, 0);
2,741✔
6897
  if (NULL == pColInfo) {
2,741✔
UNCOV
6898
    return TSDB_CODE_OUT_OF_RANGE;
×
6899
  }
6900

6901
  if (pData->totalRows == 0) {
2,741✔
6902
    pData->minRows = 0;
1,502✔
6903
  }
6904

6905
  int32_t row = 0;
2,741✔
6906
  char    st[256] = {0};
2,741✔
6907
  double  averageSize = 0;
2,741✔
6908
  if (pData->numOfBlocks != 0) {
2,741✔
6909
    averageSize = ((double)pData->totalSize) / pData->numOfBlocks;
1,239✔
6910
  }
6911
  uint64_t totalRawSize = pData->totalRows * pData->rowSize;
2,741✔
6912
  double   compRatio = 0;
2,741✔
6913
  if (totalRawSize != 0) {
2,741✔
6914
    compRatio = pData->totalSize * 100 / (double)totalRawSize;
1,239✔
6915
  }
6916

6917
  int32_t len = tsnprintf(varDataVal(st), sizeof(st) - VARSTR_HEADER_SIZE,
2,741✔
6918
                          "Total_Blocks=[%d] Total_Size=[%.2f KiB] Average_size=[%.2f KiB] Compression_Ratio=[%.2f %c]",
6919
                          pData->numOfBlocks, pData->totalSize / 1024.0, averageSize / 1024.0, compRatio, '%');
2,741✔
6920

6921
  varDataSetLen(st, len);
2,741✔
6922
  int32_t code = colDataSetVal(pColInfo, row++, st, false);
2,741✔
6923
  if (TSDB_CODE_SUCCESS != code) {
2,741✔
6924
    return code;
×
6925
  }
6926

6927
  int64_t avgRows = 0;
2,741✔
6928
  if (pData->numOfBlocks > 0) {
2,741✔
6929
    avgRows = pData->totalRows / pData->numOfBlocks;
1,239✔
6930
  }
6931

6932
  len = tsnprintf(varDataVal(st), sizeof(st) - VARSTR_HEADER_SIZE,
2,741✔
6933
                  "Block_Rows=[%" PRId64 "] MinRows=[%d] MaxRows=[%d] AvgRows=[%" PRId64 "]", pData->totalRows,
6934
                  pData->minRows, pData->maxRows, avgRows);
6935
  varDataSetLen(st, len);
2,741✔
6936
  code = colDataSetVal(pColInfo, row++, st, false);
2,741✔
6937
  if (TSDB_CODE_SUCCESS != code) {
2,741✔
UNCOV
6938
    return code;
×
6939
  }
6940

6941
  len = tsnprintf(varDataVal(st), sizeof(st) - VARSTR_HEADER_SIZE, "Inmem_Rows=[%u] Stt_Rows=[%u] ",
2,741✔
6942
                  pData->numOfInmemRows, pData->numOfSttRows);
6943
  varDataSetLen(st, len);
2,741✔
6944
  code = colDataSetVal(pColInfo, row++, st, false);
2,741✔
6945
  if (TSDB_CODE_SUCCESS != code) {
2,741✔
UNCOV
6946
    return code;
×
6947
  }
6948

6949
  len = tsnprintf(varDataVal(st), sizeof(st) - VARSTR_HEADER_SIZE,
5,482✔
6950
                  "Total_Tables=[%d] Total_Filesets=[%d] Total_Vgroups=[%d]", pData->numOfTables, pData->numOfFiles,
2,741✔
6951
                  pData->numOfVgroups);
6952

6953
  varDataSetLen(st, len);
2,741✔
6954
  code = colDataSetVal(pColInfo, row++, st, false);
2,741✔
6955
  if (TSDB_CODE_SUCCESS != code) {
2,741✔
UNCOV
6956
    return code;
×
6957
  }
6958

6959
  len = tsnprintf(varDataVal(st), sizeof(st) - VARSTR_HEADER_SIZE,
2,741✔
6960
                  "--------------------------------------------------------------------------------");
6961
  varDataSetLen(st, len);
2,741✔
6962
  code = colDataSetVal(pColInfo, row++, st, false);
2,741✔
6963
  if (TSDB_CODE_SUCCESS != code) {
2,741✔
UNCOV
6964
    return code;
×
6965
  }
6966

6967
  int32_t maxVal = 0;
2,741✔
6968
  int32_t minVal = INT32_MAX;
2,741✔
6969
  for (int32_t i = 0; i < tListLen(pData->blockRowsHisto); ++i) {
57,561✔
6970
    if (maxVal < pData->blockRowsHisto[i]) {
54,820✔
6971
      maxVal = pData->blockRowsHisto[i];
1,779✔
6972
    }
6973

6974
    if (minVal > pData->blockRowsHisto[i]) {
54,820✔
6975
      minVal = pData->blockRowsHisto[i];
3,440✔
6976
    }
6977
  }
6978

6979
  // maximum number of step is 80
6980
  double factor = pData->numOfBlocks / 80.0;
2,741✔
6981

6982
  int32_t numOfBuckets = sizeof(pData->blockRowsHisto) / sizeof(pData->blockRowsHisto[0]);
2,741✔
6983
  int32_t bucketRange = ceil(((double)(pData->defMaxRows - pData->defMinRows)) / numOfBuckets);
2,741✔
6984

6985
  for (int32_t i = 0; i < tListLen(pData->blockRowsHisto); ++i) {
57,561✔
6986
    len =
54,820✔
6987
        tsnprintf(varDataVal(st), sizeof(st) - VARSTR_HEADER_SIZE, "%04d |", pData->defMinRows + bucketRange * (i + 1));
54,820✔
6988

6989
    int32_t num = 0;
54,820✔
6990
    if (pData->blockRowsHisto[i] > 0) {
54,820✔
6991
      num = (pData->blockRowsHisto[i]) / factor;
2,859✔
6992
    }
6993

6994
    for (int32_t j = 0; j < num; ++j) {
153,400✔
6995
      int32_t x = tsnprintf(varDataVal(st) + len, sizeof(st) - VARSTR_HEADER_SIZE - len, "%c", '|');
98,580✔
6996
      len += x;
98,580✔
6997
    }
6998

6999
    if (pData->blockRowsHisto[i] > 0) {
54,820✔
7000
      double v = pData->blockRowsHisto[i] * 100.0 / pData->numOfBlocks;
2,859✔
7001
      len += tsnprintf(varDataVal(st) + len, sizeof(st) - VARSTR_HEADER_SIZE - len, "  %d (%.2f%c)",
2,859✔
7002
                       pData->blockRowsHisto[i], v, '%');
7003
    }
7004

7005
    varDataSetLen(st, len);
54,820✔
7006
    code = colDataSetVal(pColInfo, row++, st, false);
54,820✔
7007
    if (TSDB_CODE_SUCCESS != code) {
54,820✔
UNCOV
7008
      return code;
×
7009
    }
7010
  }
7011

7012
  return TSDB_CODE_SUCCESS;
2,741✔
7013
}
7014
int32_t blockDBUsageSetup(SqlFunctionCtx* pCtx, SResultRowEntryInfo* pResultInfo) {
344✔
7015
  if (pResultInfo->initialized) {
344✔
UNCOV
7016
    return TSDB_CODE_SUCCESS;
×
7017
  }
7018
  if (TSDB_CODE_SUCCESS != functionSetup(pCtx, pResultInfo)) {
344✔
UNCOV
7019
    return TSDB_CODE_FUNC_SETUP_ERROR;
×
7020
  }
7021

7022
  SDBBlockUsageInfo* pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
344✔
7023
  return TSDB_CODE_SUCCESS;
344✔
7024
}
7025
int32_t blockDBUsageFunction(SqlFunctionCtx* pCtx) {
688✔
7026
  const int32_t BLOCK_DISK_USAGE_RESULT_ROWS = 2;
688✔
7027

7028
  SInputColumnInfoData* pInput = &pCtx->input;
688✔
7029
  SColumnInfoData*      pInputCol = pInput->pData[0];
688✔
7030
  SResultRowEntryInfo*  pResInfo = GET_RES_INFO(pCtx);
688✔
7031
  SDBBlockUsageInfo*    pDistInfo = GET_ROWCELL_INTERBUF(pResInfo);
688✔
7032

7033
  SDBBlockUsageInfo p1 = {0};
688✔
7034
  if (tDeserializeBlockDbUsage(varDataVal(pInputCol->pData), varDataLen(pInputCol->pData), &p1) < 0) {
688✔
UNCOV
7035
    qError("failed to deserialize block dist info");
×
UNCOV
7036
    return TSDB_CODE_FAILED;
×
7037
  }
7038

7039
  pDistInfo->dataInDiskSize += p1.dataInDiskSize;
688✔
7040
  pDistInfo->walInDiskSize += p1.walInDiskSize;
688✔
7041
  pDistInfo->rawDataSize += p1.rawDataSize;
688✔
7042
  pResInfo->numOfRes = BLOCK_DISK_USAGE_RESULT_ROWS;  // default output rows
688✔
7043
  return TSDB_CODE_SUCCESS;
688✔
7044
}
7045

7046
int32_t tSerializeBlockDbUsage(void* buf, int32_t bufLen, const SDBBlockUsageInfo* pInfo) {
1,376✔
7047
  SEncoder encoder = {0};
1,376✔
7048
  int32_t  code = 0;
1,376✔
7049
  int32_t  lino;
7050
  int32_t  tlen;
7051
  tEncoderInit(&encoder, buf, bufLen);
1,376✔
7052

7053
  TAOS_CHECK_EXIT(tStartEncode(&encoder));
1,376✔
7054

7055
  TAOS_CHECK_EXIT(tEncodeU64(&encoder, pInfo->dataInDiskSize));
2,752✔
7056
  TAOS_CHECK_EXIT(tEncodeU64(&encoder, pInfo->walInDiskSize));
2,752✔
7057
  TAOS_CHECK_EXIT(tEncodeU64(&encoder, pInfo->rawDataSize));
2,752✔
7058

7059
  tEndEncode(&encoder);
1,376✔
7060

7061
_exit:
1,376✔
7062
  if (code) {
1,376✔
UNCOV
7063
    tlen = code;
×
7064
  } else {
7065
    tlen = encoder.pos;
1,376✔
7066
  }
7067
  tEncoderClear(&encoder);
1,376✔
7068
  return tlen;
1,376✔
7069
}
7070
int32_t tDeserializeBlockDbUsage(void* buf, int32_t bufLen, SDBBlockUsageInfo* pInfo) {
688✔
7071
  SDecoder decoder = {0};
688✔
7072
  int32_t  code = 0;
688✔
7073
  int32_t  lino;
7074
  tDecoderInit(&decoder, buf, bufLen);
688✔
7075

7076
  TAOS_CHECK_EXIT(tStartDecode(&decoder));
688✔
7077
  TAOS_CHECK_EXIT(tDecodeU64(&decoder, &pInfo->dataInDiskSize));
1,376✔
7078
  TAOS_CHECK_EXIT(tDecodeU64(&decoder, &pInfo->walInDiskSize));
1,376✔
7079
  TAOS_CHECK_EXIT(tDecodeU64(&decoder, &pInfo->rawDataSize));
1,376✔
7080

7081
_exit:
688✔
7082
  tDecoderClear(&decoder);
688✔
7083
  return code;
688✔
7084
}
7085
int32_t blockDBUsageFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
344✔
7086
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
344✔
7087
  SDBBlockUsageInfo*   pData = GET_ROWCELL_INTERBUF(pResInfo);
344✔
7088

7089
  SColumnInfoData* pColInfo = taosArrayGet(pBlock->pDataBlock, 0);
344✔
7090
  if (NULL == pColInfo) {
344✔
UNCOV
7091
    return TSDB_CODE_OUT_OF_RANGE;
×
7092
  }
7093
  int32_t len = 0;
344✔
7094
  int32_t row = 0;
344✔
7095
  char    st[256] = {0};
344✔
7096

7097
  uint64_t totalDiskSize = pData->dataInDiskSize;
344✔
7098
  uint64_t rawDataSize = pData->rawDataSize;
344✔
7099
  double   compressRatio = 0;
344✔
7100
  if (rawDataSize != 0) {
344✔
7101
    compressRatio = totalDiskSize * 100 / (double)rawDataSize;
172✔
7102
    len = tsnprintf(varDataVal(st), sizeof(st) - VARSTR_HEADER_SIZE, "Compress_ratio=[%.2f%]", compressRatio);
172✔
7103
  } else {
7104
    len = tsnprintf(varDataVal(st), sizeof(st) - VARSTR_HEADER_SIZE, "Compress_ratio=[NULL]");
172✔
7105
  }
7106

7107
  varDataSetLen(st, len);
344✔
7108
  int32_t code = colDataSetVal(pColInfo, row++, st, false);
344✔
7109
  if (TSDB_CODE_SUCCESS != code) {
344✔
UNCOV
7110
    return code;
×
7111
  }
7112

7113
  len =
344✔
7114
      tsnprintf(varDataVal(st), sizeof(st) - VARSTR_HEADER_SIZE, "Disk_occupied=[%" PRId64 "k]", pData->dataInDiskSize);
344✔
7115
  varDataSetLen(st, len);
344✔
7116
  code = colDataSetVal(pColInfo, row++, st, false);
344✔
7117
  if (TSDB_CODE_SUCCESS != code) {
344✔
UNCOV
7118
    return code;
×
7119
  }
7120
  return code;
344✔
7121
}
7122

7123
bool getDerivativeFuncEnv(struct SFunctionNode* pFunc, SFuncExecEnv* pEnv) {
187,610✔
7124
  pEnv->calcMemSize = sizeof(SDerivInfo);
187,610✔
7125
  return true;
187,610✔
7126
}
7127

7128
int32_t derivativeFuncSetup(SqlFunctionCtx* pCtx, SResultRowEntryInfo* pResInfo) {
627,611✔
7129
  if (pResInfo->initialized) {
627,611✔
7130
    return TSDB_CODE_SUCCESS;
412,150✔
7131
  }
7132
  if (TSDB_CODE_SUCCESS != functionSetup(pCtx, pResInfo)) {
215,461✔
UNCOV
7133
    return TSDB_CODE_FUNC_SETUP_ERROR;
×
7134
  }
7135

7136
  SDerivInfo* pDerivInfo = GET_ROWCELL_INTERBUF(pResInfo);
215,461✔
7137

7138
  pDerivInfo->ignoreNegative = pCtx->param[2].param.i;
215,461✔
7139
  pDerivInfo->prevTs = -1;
215,461✔
7140
  pDerivInfo->tsWindow = pCtx->param[1].param.i;
215,461✔
7141
  pDerivInfo->valueSet = false;
215,461✔
7142
  return TSDB_CODE_SUCCESS;
215,461✔
7143
}
7144

7145
int32_t derivativeFunction(SqlFunctionCtx* pCtx) { return TSDB_CODE_SUCCESS; }
440,001✔
7146

7147
static int32_t DoDerivativeFunction(SqlFunctionCtx* pCtx) {
440,001✔
7148
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
440,001✔
7149
  SDerivInfo*          pDerivInfo = GET_ROWCELL_INTERBUF(pResInfo);
440,001✔
7150

7151
  SInputColumnInfoData* pInput = &pCtx->input;
440,001✔
7152
  SColumnInfoData*      pInputCol = pInput->pData[0];
440,001✔
7153

7154
  int32_t          numOfElems = 0;
440,001✔
7155
  SColumnInfoData* pOutput = (SColumnInfoData*)pCtx->pOutput;
440,001✔
7156
  SColumnInfoData* pTsOutput = pCtx->pTsOutput;
440,001✔
7157
  int32_t          code = TSDB_CODE_SUCCESS;
440,001✔
7158

7159
  funcInputUpdate(pCtx);
440,001✔
7160

7161
  double v = 0;
440,001✔
7162
  if (pCtx->order == TSDB_ORDER_ASC) {
440,001✔
7163
    SFuncInputRow row = {0};
438,517✔
7164
    bool          result = false;
438,517✔
7165
    while (1) {
151,986,785✔
7166
      code = funcInputGetNextRow(pCtx, &row, &result);
152,425,302✔
7167
      if (TSDB_CODE_SUCCESS != code) {
152,425,302✔
7168
        return code;
×
7169
      }
7170
      if (!result) {
152,425,302✔
7171
        break;
438,517✔
7172
      }
7173
      if (row.isDataNull) {
151,986,785✔
7174
        continue;
2,325,084✔
7175
      }
7176

7177
      char* d = row.pData;
149,661,701✔
7178
      GET_TYPED_DATA(v, double, pInputCol->info.type, d, typeGetTypeModFromColInfo(&pInputCol->info));
149,661,701✔
7179

7180
      int32_t pos = pCtx->offset + numOfElems;
149,661,701✔
7181
      if (!pDerivInfo->valueSet) {  // initial value is not set yet
149,661,701✔
7182
        pDerivInfo->valueSet = true;
188,219✔
7183
      } else {
7184
        if (row.ts == pDerivInfo->prevTs) {
149,473,482✔
UNCOV
7185
          return TSDB_CODE_FUNC_DUP_TIMESTAMP;
×
7186
        }
7187
        double r = ((v - pDerivInfo->prevValue) * pDerivInfo->tsWindow) / (row.ts - pDerivInfo->prevTs);
149,473,482✔
7188
        if (pDerivInfo->ignoreNegative && r < 0) {
149,473,482✔
7189
        } else {
7190
          if (isinf(r) || isnan(r)) {
139,829,120✔
UNCOV
7191
            colDataSetNULL(pOutput, pos);
×
7192
          } else {
7193
            code = colDataSetVal(pOutput, pos, (const char*)&r, false);
139,829,120✔
7194
            if (code != TSDB_CODE_SUCCESS) {
139,829,120✔
UNCOV
7195
              return code;
×
7196
            }
7197
          }
7198

7199
          if (pTsOutput != NULL) {
139,829,120✔
UNCOV
7200
            colDataSetInt64(pTsOutput, pos, &row.ts);
×
7201
          }
7202

7203
          // handle selectivity
7204
          if (pCtx->subsidiaries.num > 0) {
139,829,120✔
7205
            code = appendSelectivityCols(pCtx, row.block, row.rowIndex, pos);
1,831,456✔
7206
            if (code != TSDB_CODE_SUCCESS) {
1,831,456✔
UNCOV
7207
              return code;
×
7208
            }
7209
          }
7210

7211
          numOfElems++;
139,829,120✔
7212
        }
7213
      }
7214

7215
      pDerivInfo->prevValue = v;
149,661,701✔
7216
      pDerivInfo->prevTs = row.ts;
149,661,701✔
7217
    }
7218
  } else {
7219
    SFuncInputRow row = {0};
1,484✔
7220
    bool          result = false;
1,484✔
7221
    while (1) {
2,968✔
7222
      code = funcInputGetNextRow(pCtx, &row, &result);
4,452✔
7223
      if (TSDB_CODE_SUCCESS != code) {
4,452✔
7224
        return code;
×
7225
      }
7226
      if (!result) {
4,452✔
7227
        break;
1,484✔
7228
      }
7229
      if (row.isDataNull) {
2,968✔
7230
        continue;
1,996✔
7231
      }
7232

7233
      char* d = row.pData;
972✔
7234
      GET_TYPED_DATA(v, double, pInputCol->info.type, d, typeGetTypeModFromColInfo(&pInputCol->info));
972✔
7235

7236
      int32_t pos = pCtx->offset + numOfElems;
972✔
7237
      if (!pDerivInfo->valueSet) {  // initial value is not set yet
972✔
7238
        pDerivInfo->valueSet = true;
486✔
7239
      } else {
7240
        if (row.ts == pDerivInfo->prevTs) {
486✔
UNCOV
7241
          return TSDB_CODE_FUNC_DUP_TIMESTAMP;
×
7242
        }
7243
        double r = ((pDerivInfo->prevValue - v) * pDerivInfo->tsWindow) / (pDerivInfo->prevTs - row.ts);
486✔
7244
        if (pDerivInfo->ignoreNegative && r < 0) {
486✔
7245
        } else {
7246
          if (isinf(r) || isnan(r)) {
486✔
UNCOV
7247
            colDataSetNULL(pOutput, pos);
×
7248
          } else {
7249
            code = colDataSetVal(pOutput, pos, (const char*)&r, false);
486✔
7250
            if (code != TSDB_CODE_SUCCESS) {
486✔
UNCOV
7251
              return code;
×
7252
            }
7253
          }
7254

7255
          if (pTsOutput != NULL) {
486✔
UNCOV
7256
            colDataSetInt64(pTsOutput, pos, &pDerivInfo->prevTs);
×
7257
          }
7258

7259
          // handle selectivity
7260
          if (pCtx->subsidiaries.num > 0) {
486✔
UNCOV
7261
            code = appendSelectivityCols(pCtx, row.block, row.rowIndex, pos);
×
UNCOV
7262
            if (code != TSDB_CODE_SUCCESS) {
×
UNCOV
7263
              return code;
×
7264
            }
7265
          }
7266
          numOfElems++;
486✔
7267
        }
7268
      }
7269

7270
      pDerivInfo->prevValue = v;
972✔
7271
      pDerivInfo->prevTs = row.ts;
972✔
7272
    }
7273
  }
7274

7275
  pResInfo->numOfRes = numOfElems;
440,001✔
7276

7277
  return TSDB_CODE_SUCCESS;
440,001✔
7278
}
7279

7280
int32_t derivativeFunctionByRow(SArray* pCtxArray) {
440,001✔
7281
  for (int32_t i = 0; i < taosArrayGetSize(pCtxArray); ++i) {
880,002✔
7282
    SqlFunctionCtx* pCtx = *(SqlFunctionCtx**)taosArrayGet(pCtxArray, i);
440,001✔
7283
    int32_t         code = DoDerivativeFunction(pCtx);
440,001✔
7284
    if (code != TSDB_CODE_SUCCESS) {
440,001✔
UNCOV
7285
      return code;
×
7286
    }
7287
  }
7288
  return TSDB_CODE_SUCCESS;
440,001✔
7289
}
7290

7291
int32_t getIrateInfoSize(int32_t pkBytes) { return (int32_t)sizeof(SRateInfo) + 2 * pkBytes; }
228,638✔
7292

7293
bool getIrateFuncEnv(struct SFunctionNode* pFunc, SFuncExecEnv* pEnv) {
189,099✔
7294
  int32_t pkBytes = (pFunc->hasPk) ? pFunc->pkBytes : 0;
189,099✔
7295
  pEnv->calcMemSize = getIrateInfoSize(pkBytes);
189,099✔
7296
  return true;
189,099✔
7297
}
7298

7299
int32_t irateFuncSetup(SqlFunctionCtx* pCtx, SResultRowEntryInfo* pResInfo) {
1,744,599✔
7300
  if (pResInfo->initialized) {
1,744,599✔
UNCOV
7301
    return TSDB_CODE_SUCCESS;
×
7302
  }
7303
  if (TSDB_CODE_SUCCESS != functionSetup(pCtx, pResInfo)) {
1,744,599✔
UNCOV
7304
    return TSDB_CODE_FUNC_SETUP_ERROR;
×
7305
  }
7306

7307
  SRateInfo* pInfo = GET_ROWCELL_INTERBUF(pResInfo);
1,744,599✔
7308

7309
  pInfo->firstKey = INT64_MIN;
1,744,599✔
7310
  pInfo->lastKey = INT64_MIN;
1,744,599✔
7311
  pInfo->firstValue = (double)INT64_MIN;
1,744,599✔
7312
  pInfo->lastValue = (double)INT64_MIN;
1,744,599✔
7313

7314
  pInfo->hasResult = 0;
1,744,599✔
7315
  return TSDB_CODE_SUCCESS;
1,744,599✔
7316
}
7317

7318
static void doSaveRateInfo(SRateInfo* pRateInfo, bool isFirst, int64_t ts, char* pk, double v) {
346,122,902✔
7319
  if (isFirst) {
346,122,902✔
7320
    pRateInfo->firstValue = v;
172,636,717✔
7321
    pRateInfo->firstKey = ts;
172,636,717✔
7322
    if (pRateInfo->firstPk) {
172,636,717✔
7323
      int32_t pkBytes;
7324
      if (IS_VAR_DATA_TYPE(pRateInfo->pkType)) {
23,275✔
7325
        pkBytes = calcStrBytesByType(pRateInfo->pkType, pk);
5,320✔
7326
      } else {
7327
        pkBytes = pRateInfo->pkBytes;
17,955✔
7328
      }
7329
      (void)memcpy(pRateInfo->firstPk, pk, pkBytes);
23,275✔
7330
    }
7331
  } else {
7332
    pRateInfo->lastValue = v;
173,486,185✔
7333
    pRateInfo->lastKey = ts;
173,487,021✔
7334
    if (pRateInfo->lastPk) {
173,487,021✔
7335
      int32_t pkBytes;
7336
      if (IS_VAR_DATA_TYPE(pRateInfo->pkType)) {
34,580✔
7337
        pkBytes = calcStrBytesByType(pRateInfo->pkType, pk);
7,980✔
7338
      } else {
7339
        pkBytes = pRateInfo->pkBytes;
26,600✔
7340
      }
7341
      (void)memcpy(pRateInfo->lastPk, pk, pkBytes);
34,580✔
7342
    }
7343
  }
7344
}
346,123,738✔
7345

7346
static void initializeRateInfo(SqlFunctionCtx* pCtx, SRateInfo* pRateInfo, bool isMerge) {
1,961,061✔
7347
  if (pCtx->hasPrimaryKey) {
1,961,061✔
7348
    if (!isMerge) {
12,635✔
7349
      pRateInfo->pkType = pCtx->input.pPrimaryKey->info.type;
11,305✔
7350
      pRateInfo->pkBytes = pCtx->input.pPrimaryKey->info.bytes;
11,305✔
7351
      pRateInfo->firstPk = pRateInfo->pkData;
11,305✔
7352
      pRateInfo->lastPk = pRateInfo->pkData + pRateInfo->pkBytes;
11,305✔
7353
    } else {
7354
      pRateInfo->firstPk = pRateInfo->pkData;
1,330✔
7355
      pRateInfo->lastPk = pRateInfo->pkData + pRateInfo->pkBytes;
1,330✔
7356
    }
7357
  } else {
7358
    pRateInfo->firstPk = NULL;
1,948,426✔
7359
    pRateInfo->lastPk = NULL;
1,948,426✔
7360
  }
7361
}
1,961,061✔
7362

7363
int32_t irateFunction(SqlFunctionCtx* pCtx) {
1,902,975✔
7364
  int32_t              code = TSDB_CODE_SUCCESS;
1,902,975✔
7365
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
1,902,975✔
7366
  SRateInfo*           pRateInfo = GET_ROWCELL_INTERBUF(pResInfo);
1,902,975✔
7367

7368
  SInputColumnInfoData* pInput = &pCtx->input;
1,902,975✔
7369
  SColumnInfoData*      pInputCol = pInput->pData[0];
1,902,975✔
7370

7371
  SColumnInfoData* pOutput = (SColumnInfoData*)pCtx->pOutput;
1,902,975✔
7372

7373
  funcInputUpdate(pCtx);
1,902,975✔
7374

7375
  initializeRateInfo(pCtx, pRateInfo, false);
1,902,975✔
7376

7377
  int32_t       numOfElems = 0;
1,902,975✔
7378
  int32_t       type = pInputCol->info.type;
1,902,975✔
7379
  SFuncInputRow row = {0};
1,902,975✔
7380
  bool          result = false;
1,902,975✔
7381
  while (1) {
237,126,291✔
7382
    code = funcInputGetNextRow(pCtx, &row, &result);
239,029,266✔
7383
    if (TSDB_CODE_SUCCESS != code) {
239,029,684✔
7384
      return code;
×
7385
    }
7386
    if (!result) {
239,029,684✔
7387
      break;
1,902,975✔
7388
    }
7389
    if (row.isDataNull) {
237,126,709✔
7390
      continue;
7,686,418✔
7391
    }
7392

7393
    char*  data = row.pData;
229,440,291✔
7394
    double v = 0;
229,440,291✔
7395
    GET_TYPED_DATA(v, double, type, data, typeGetTypeModFromColInfo(&pInputCol->info));
229,440,291✔
7396

7397
    if (INT64_MIN == pRateInfo->lastKey) {
229,440,291✔
7398
      doSaveRateInfo(pRateInfo, false, row.ts, row.pPk, v);
852,138✔
7399
      pRateInfo->hasResult = 1;
852,138✔
7400
      continue;
852,138✔
7401
    }
7402

7403
    if (row.ts > pRateInfo->lastKey) {
228,587,735✔
7404
      if ((INT64_MIN == pRateInfo->firstKey) || pRateInfo->lastKey > pRateInfo->firstKey) {
172,606,258✔
7405
        doSaveRateInfo(pRateInfo, true, pRateInfo->lastKey, pRateInfo->lastPk, pRateInfo->lastValue);
172,606,258✔
7406
      }
7407
      doSaveRateInfo(pRateInfo, false, row.ts, row.pPk, v);
172,606,258✔
7408
      continue;
172,606,258✔
7409
    } else if (row.ts == pRateInfo->lastKey) {
55,981,477✔
7410
      return TSDB_CODE_FUNC_DUP_TIMESTAMP;
×
7411
    }
7412

7413
    if ((INT64_MIN == pRateInfo->firstKey) || row.ts > pRateInfo->firstKey) {
55,981,477✔
7414
      doSaveRateInfo(pRateInfo, true, row.ts, row.pPk, v);
998✔
7415
    } else if (row.ts == pRateInfo->firstKey) {
55,980,479✔
UNCOV
7416
      return TSDB_CODE_FUNC_DUP_TIMESTAMP;
×
7417
    }
7418
  }
7419

7420
  numOfElems++;
1,902,975✔
7421

7422
  SET_VAL(pResInfo, numOfElems, 1);
1,902,975✔
7423
  return TSDB_CODE_SUCCESS;
1,902,975✔
7424
}
7425

7426
static double doCalcRate(const SRateInfo* pRateInfo, double tickPerSec) {
1,715,556✔
7427
  if ((INT64_MIN == pRateInfo->lastKey) || (INT64_MIN == pRateInfo->firstKey) ||
1,715,556✔
7428
      (pRateInfo->firstKey >= pRateInfo->lastKey)) {
118,727✔
7429
    return 0.0;
1,596,829✔
7430
  }
7431

7432
  double diff = 0;
118,727✔
7433
  // If the previous value of the last is greater than the last value, only keep the last point instead of the delta
7434
  // value between two values.
7435
  diff = pRateInfo->lastValue;
118,727✔
7436
  if (diff >= pRateInfo->firstValue) {
118,727✔
7437
    diff -= pRateInfo->firstValue;
79,347✔
7438
  }
7439

7440
  int64_t duration = pRateInfo->lastKey - pRateInfo->firstKey;
118,727✔
7441
  if (duration == 0) {
118,727✔
UNCOV
7442
    return 0;
×
7443
  }
7444

7445
  return (duration > 0) ? ((double)diff) / (duration / tickPerSec) : 0.0;
118,727✔
7446
}
7447

7448
static void irateTransferInfoImpl(TSKEY inputKey, SRateInfo* pInput, SRateInfo* pOutput, bool isFirstKey) {
23,884✔
7449
  if (inputKey > pOutput->lastKey) {
23,884✔
7450
    doSaveRateInfo(pOutput, true, pOutput->lastKey, pOutput->lastPk, pOutput->lastValue);
13,434✔
7451
    if (isFirstKey) {
13,434✔
7452
      doSaveRateInfo(pOutput, false, pInput->firstKey, pInput->firstPk, pInput->firstValue);
5,672✔
7453
    } else {
7454
      doSaveRateInfo(pOutput, false, pInput->lastKey, pInput->lastPk, pInput->lastValue);
7,762✔
7455
    }
7456
  } else if ((inputKey < pOutput->lastKey) && (inputKey > pOutput->firstKey)) {
10,450✔
7457
    if (isFirstKey) {
836✔
7458
      doSaveRateInfo(pOutput, true, pInput->firstKey, pInput->firstPk, pInput->firstValue);
418✔
7459
    } else {
7460
      doSaveRateInfo(pOutput, true, pInput->lastKey, pInput->lastPk, pInput->lastValue);
418✔
7461
    }
7462
  } else {
7463
    // inputKey < pOutput->firstKey
7464
  }
7465
}
23,884✔
7466

7467
static void irateCopyInfo(SRateInfo* pInput, SRateInfo* pOutput) {
15,191✔
7468
  doSaveRateInfo(pOutput, true, pInput->firstKey, pInput->firstPk, pInput->firstValue);
15,191✔
7469
  doSaveRateInfo(pOutput, false, pInput->lastKey, pInput->lastPk, pInput->lastValue);
15,191✔
7470
}
15,191✔
7471

7472
static int32_t irateTransferInfo(SRateInfo* pInput, SRateInfo* pOutput) {
27,133✔
7473
  if ((pInput->firstKey != INT64_MIN &&
27,133✔
7474
       (pInput->firstKey == pOutput->firstKey || pInput->firstKey == pOutput->lastKey)) ||
24,549✔
7475
      (pInput->lastKey != INT64_MIN && (pInput->lastKey == pOutput->firstKey || pInput->lastKey == pOutput->lastKey))) {
27,133✔
UNCOV
7476
    return TSDB_CODE_FUNC_DUP_TIMESTAMP;
×
7477
  }
7478

7479
  if (pOutput->hasResult == 0) {
27,133✔
7480
    irateCopyInfo(pInput, pOutput);
15,191✔
7481
    pOutput->hasResult = pInput->hasResult;
15,191✔
7482
    return TSDB_CODE_SUCCESS;
15,191✔
7483
  }
7484

7485
  if (pInput->firstKey != INT64_MIN) {
11,942✔
7486
    irateTransferInfoImpl(pInput->firstKey, pInput, pOutput, true);
11,942✔
7487
  }
7488

7489
  if (pInput->lastKey != INT64_MIN) {
11,942✔
7490
    irateTransferInfoImpl(pInput->lastKey, pInput, pOutput, false);
11,942✔
7491
  }
7492

7493
  pOutput->hasResult = pInput->hasResult;
11,942✔
7494
  return TSDB_CODE_SUCCESS;
11,942✔
7495
}
7496

7497
int32_t irateFunctionMerge(SqlFunctionCtx* pCtx) {
29,043✔
7498
  SInputColumnInfoData* pInput = &pCtx->input;
29,043✔
7499
  SColumnInfoData*      pCol = pInput->pData[0];
29,043✔
7500
  if (pCol->info.type != TSDB_DATA_TYPE_BINARY) {
29,043✔
UNCOV
7501
    return TSDB_CODE_FUNC_FUNTION_PARA_TYPE;
×
7502
  }
7503

7504
  SRateInfo* pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
29,043✔
7505
  initializeRateInfo(pCtx, pInfo, true);
29,043✔
7506

7507
  int32_t start = pInput->startRowIndex;
29,043✔
7508
  for (int32_t i = start; i < start + pInput->numOfRows; ++i) {
58,086✔
7509
    char*      data = colDataGetData(pCol, i);
29,043✔
7510
    SRateInfo* pInputInfo = (SRateInfo*)varDataVal(data);
29,043✔
7511
    initializeRateInfo(pCtx, pInfo, true);
29,043✔
7512
    if (pInputInfo->hasResult) {
29,043✔
7513
      int32_t code = irateTransferInfo(pInputInfo, pInfo);
27,133✔
7514
      if (code != TSDB_CODE_SUCCESS) {
27,133✔
UNCOV
7515
        return code;
×
7516
      }
7517
    }
7518
  }
7519

7520
  if (pInfo->hasResult) {
29,043✔
7521
    GET_RES_INFO(pCtx)->numOfRes = 1;
27,133✔
7522
  }
7523

7524
  return TSDB_CODE_SUCCESS;
29,043✔
7525
}
7526

7527
int32_t iratePartialFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
29,043✔
7528
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
29,043✔
7529
  SRateInfo*           pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
29,043✔
7530
  int32_t              resultBytes = getIrateInfoSize(pInfo->pkBytes);
29,043✔
7531
  char*                res = taosMemoryCalloc(resultBytes + VARSTR_HEADER_SIZE, sizeof(char));
29,043✔
7532

7533
  if (NULL == res) {
29,043✔
UNCOV
7534
    return terrno;
×
7535
  }
7536
  (void)memcpy(varDataVal(res), pInfo, resultBytes);
29,043✔
7537
  varDataSetLen(res, resultBytes);
29,043✔
7538

7539
  int32_t          slotId = pCtx->pExpr->base.resSchema.slotId;
29,043✔
7540
  SColumnInfoData* pCol = taosArrayGet(pBlock->pDataBlock, slotId);
29,043✔
7541
  if (NULL == pCol) {
29,043✔
UNCOV
7542
    taosMemoryFree(res);
×
UNCOV
7543
    return TSDB_CODE_OUT_OF_RANGE;
×
7544
  }
7545

7546
  int32_t code = colDataSetVal(pCol, pBlock->info.rows, res, false);
29,043✔
7547

7548
  taosMemoryFree(res);
29,043✔
7549
  return code;
29,043✔
7550
}
7551

7552
int32_t irateFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
1,715,556✔
7553
  int32_t          slotId = pCtx->pExpr->base.resSchema.slotId;
1,715,556✔
7554
  SColumnInfoData* pCol = taosArrayGet(pBlock->pDataBlock, slotId);
1,715,556✔
7555
  if (NULL == pCol) {
1,715,556✔
UNCOV
7556
    return TSDB_CODE_OUT_OF_RANGE;
×
7557
  }
7558

7559
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
1,715,556✔
7560
  pResInfo->isNullRes = (pResInfo->numOfRes == 0) ? 1 : 0;
1,715,556✔
7561

7562
  SRateInfo* pInfo = GET_ROWCELL_INTERBUF(pResInfo);
1,715,556✔
7563
  double     result = doCalcRate(pInfo, (double)TSDB_TICK_PER_SECOND(pCtx->param[1].param.i));
1,715,556✔
7564
  int32_t    code = colDataSetVal(pCol, pBlock->info.rows, (const char*)&result, pResInfo->isNullRes);
1,715,556✔
7565

7566
  return code;
1,715,556✔
7567
}
7568

7569
int32_t groupConstValueFunction(SqlFunctionCtx* pCtx) {
2,147,483,647✔
7570
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
2,147,483,647✔
7571
  SGroupKeyInfo*       pInfo = GET_ROWCELL_INTERBUF(pResInfo);
2,147,483,647✔
7572
  bool                 isWindow = pCtx->hasWindowOrGroup && pCtx->hasWindow;
2,147,483,647✔
7573

7574
  if (pInfo->hasResult && (!isWindow || !pInfo->isNull)) {
2,147,483,647✔
7575
    // If already has result for 'group by' or
7576
    // has non-null result for 'window', we can skip left data blocks.
7577
    goto _group_value_over;
2,147,483,647✔
7578
  }
7579

7580
  int32_t               valueRowIndex = -1;
2,147,483,647✔
7581
  SInputColumnInfoData* pInput = &pCtx->input;
2,147,483,647✔
7582
  SColumnInfoData*      pInputCol = pInput->pData[0];
2,147,483,647✔
7583

7584
  // try to find a non-null value
7585
  if (NULL != pInputCol->pData) {
2,147,483,647✔
7586
    if (isWindow) {
2,147,483,647✔
7587
      // for 'window', non-null value can appear at any row of any data block
7588
      int64_t startIndex = pInput->startRowIndex;
2,147,483,647✔
7589
      int64_t endIndex = pInput->startRowIndex + pInput->numOfRows - 1;
2,147,483,647✔
7590
      for (int64_t i = startIndex; i <= endIndex; ++i) {
2,147,483,647✔
7591
        if (!colDataIsNull_s(pInputCol, i)) {
2,147,483,647✔
7592
          valueRowIndex = i;
2,147,483,647✔
7593
          break;
2,147,483,647✔
7594
        }
7595
      }
7596
    } else {
7597
      // for 'group by', just take the first row
7598
      if (!colDataIsNull_s(pInputCol, pInput->startRowIndex)) {
425,274,104✔
7599
        valueRowIndex = pInput->startRowIndex;
209,470,965✔
7600
      }
7601
    }
7602
  }
7603

7604
  if (valueRowIndex != -1) {
2,147,483,647✔
7605
    // found a non-null value
7606
    char* data = colDataGetData(pInputCol, valueRowIndex);
2,147,483,647✔
7607
    if (IS_VAR_DATA_TYPE(pInputCol->info.type)) {
2,147,483,647✔
7608
      int32_t bytes = calcStrBytesByType(pInputCol->info.type, data);
2,147,483,647✔
7609
      (void)memcpy(pInfo->data, data, bytes);
2,147,483,647✔
7610
    } else {
7611
      (void)memcpy(pInfo->data, data, pInputCol->info.bytes);
2,147,483,647✔
7612
    }
7613
    pInfo->isNull = false;
2,147,483,647✔
7614
  } else {
7615
    // all values are null or first value is null for group by
7616
    pInfo->isNull = true;
460,900,959✔
7617
  }
7618
  pInfo->hasResult = true;
2,147,483,647✔
7619

7620
_group_value_over:
2,147,483,647✔
7621
  SET_VAL(pResInfo, 1, 1);
2,147,483,647✔
7622
  return TSDB_CODE_SUCCESS;
2,147,483,647✔
7623
}
7624

7625
int32_t groupKeyFunction(SqlFunctionCtx* pCtx) { return groupConstValueFunction(pCtx); }
2,147,483,647✔
7626

7627
int32_t groupConstValueFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
2,147,483,647✔
7628
  int32_t          slotId = pCtx->pExpr->base.resSchema.slotId;
2,147,483,647✔
7629
  int32_t          code = TSDB_CODE_SUCCESS;
2,147,483,647✔
7630
  SColumnInfoData* pCol = taosArrayGet(pBlock->pDataBlock, slotId);
2,147,483,647✔
7631
  if (NULL == pCol) {
2,147,483,647✔
7632
    return TSDB_CODE_OUT_OF_RANGE;
×
7633
  }
7634

7635
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
2,147,483,647✔
7636

7637
  SGroupKeyInfo* pInfo = GET_ROWCELL_INTERBUF(pResInfo);
2,147,483,647✔
7638

7639
  if (pInfo->hasResult) {
2,147,483,647✔
7640
    int32_t currentRow = pBlock->info.rows;
2,147,483,647✔
7641
    for (; currentRow < pBlock->info.rows + pResInfo->numOfRes; ++currentRow) {
2,147,483,647✔
7642
      code = colDataSetVal(pCol, currentRow, pInfo->data, pInfo->isNull ? true : false);
2,147,483,647✔
7643
      if (TSDB_CODE_SUCCESS != code) {
2,147,483,647✔
7644
        return code;
×
7645
      }
7646
    }
7647
  } else {
UNCOV
7648
    pResInfo->numOfRes = 0;
×
7649
  }
7650

7651
  return code;
2,147,483,647✔
7652
}
7653

7654
int32_t groupKeyFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) { return groupConstValueFinalize(pCtx, pBlock); }
2,147,483,647✔
7655

UNCOV
7656
int32_t groupKeyCombine(SqlFunctionCtx* pDestCtx, SqlFunctionCtx* pSourceCtx) {
×
UNCOV
7657
  SResultRowEntryInfo* pDResInfo = GET_RES_INFO(pDestCtx);
×
UNCOV
7658
  SGroupKeyInfo*       pDBuf = GET_ROWCELL_INTERBUF(pDResInfo);
×
7659

UNCOV
7660
  SResultRowEntryInfo* pSResInfo = GET_RES_INFO(pSourceCtx);
×
UNCOV
7661
  SGroupKeyInfo*       pSBuf = GET_ROWCELL_INTERBUF(pSResInfo);
×
7662

7663
  // escape rest of data blocks to avoid first entry to be overwritten.
UNCOV
7664
  if (pDBuf->hasResult) {
×
UNCOV
7665
    goto _group_key_over;
×
7666
  }
7667

UNCOV
7668
  if (pSBuf->isNull) {
×
UNCOV
7669
    pDBuf->isNull = true;
×
UNCOV
7670
    pDBuf->hasResult = true;
×
UNCOV
7671
    goto _group_key_over;
×
7672
  }
7673

UNCOV
7674
  if (IS_VAR_DATA_TYPE(pSourceCtx->resDataInfo.type)) {
×
UNCOV
7675
    int32_t bytes = calcStrBytesByType(pSourceCtx->resDataInfo.type, pSBuf->data);
×
UNCOV
7676
    (void)memcpy(pDBuf->data, pSBuf->data, bytes);
×
7677
  } else {
UNCOV
7678
    (void)memcpy(pDBuf->data, pSBuf->data, pSourceCtx->resDataInfo.bytes);
×
7679
  }
7680

UNCOV
7681
  pDBuf->hasResult = true;
×
7682

UNCOV
7683
_group_key_over:
×
7684

UNCOV
7685
  SET_VAL(pDResInfo, 1, 1);
×
UNCOV
7686
  return TSDB_CODE_SUCCESS;
×
7687
}
7688

7689
int32_t cachedLastRowFunction(SqlFunctionCtx* pCtx) {
388,223✔
7690
  int32_t numOfElems = 0;
388,223✔
7691

7692
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
388,223✔
7693
  SFirstLastRes*       pInfo = GET_ROWCELL_INTERBUF(pResInfo);
388,223✔
7694

7695
  SInputColumnInfoData* pInput = &pCtx->input;
388,223✔
7696
  SColumnInfoData*      pInputCol = pInput->pData[0];
388,223✔
7697

7698
  int32_t bytes = pInputCol->info.bytes;
388,223✔
7699
  pInfo->bytes = bytes;
388,223✔
7700

7701
  SColumnInfoData* pkCol = pInput->pPrimaryKey;
388,223✔
7702
  pInfo->pkType = -1;
388,223✔
7703
  __compar_fn_t pkCompareFn = NULL;
388,223✔
7704
  if (pCtx->hasPrimaryKey) {
388,223✔
7705
    pInfo->pkType = pkCol->info.type;
14,916✔
7706
    pInfo->pkBytes = pkCol->info.bytes;
14,916✔
7707
    pkCompareFn = getKeyComparFunc(pInfo->pkType, TSDB_ORDER_DESC);
14,916✔
7708
  }
7709

7710
  // data is guaranteed to be in descending order
7711
  for (int32_t i = pInput->numOfRows + pInput->startRowIndex - 1; i >= pInput->startRowIndex; --i) {
831,501✔
7712
    numOfElems++;
443,278✔
7713

7714
    bool  isNull = colDataIsNull(pInputCol, pInput->numOfRows, i, NULL);
443,278✔
7715
    char* data = isNull ? NULL : colDataGetData(pInputCol, i);
443,278✔
7716

7717
    TSKEY cts = getRowPTs(pInput->pPTS, i);
443,278✔
7718
    if (pResInfo->numOfRes == 0 || pInfo->ts < cts) {
443,278✔
7719
      int32_t code = doSaveLastrow(pCtx, data, i, cts, pInfo);
364,111✔
7720
      if (code != TSDB_CODE_SUCCESS) {
364,111✔
7721
        return code;
×
7722
      }
7723
      pResInfo->numOfRes = 1;
364,111✔
7724
    }
7725
  }
7726

7727
  SET_VAL(pResInfo, numOfElems, 1);
388,223✔
7728
  return TSDB_CODE_SUCCESS;
388,223✔
7729
}
7730

7731
bool getCorrFuncEnv(SFunctionNode* pFunc, SFuncExecEnv* pEnv) {
×
UNCOV
7732
  pEnv->calcMemSize = sizeof(SCorrRes);
×
7733
  return true;
×
7734
}
7735

UNCOV
7736
int32_t corrFuncSetup(SqlFunctionCtx* pCtx, SResultRowEntryInfo* pResultInfo) {
×
UNCOV
7737
  if (pResultInfo->initialized) {
×
7738
    return TSDB_CODE_SUCCESS;
×
7739
  }
UNCOV
7740
  if (TSDB_CODE_SUCCESS != functionSetup(pCtx, pResultInfo)) {
×
7741
    return TSDB_CODE_FUNC_SETUP_ERROR;
×
7742
  }
7743

UNCOV
7744
  SCorrRes* pRes = GET_ROWCELL_INTERBUF(pResultInfo);
×
7745
  (void)memset(pRes, 0, sizeof(SCorrRes));
×
7746
  return TSDB_CODE_SUCCESS;
×
7747
}
7748

7749
int32_t corrFunction(SqlFunctionCtx* pCtx) {
×
UNCOV
7750
  int32_t               numOfElem = 0;
×
7751
  SInputColumnInfoData* pInput = &pCtx->input;
×
7752
  int32_t               xType = pInput->pData[0]->info.type;
×
UNCOV
7753
  int32_t               yType = pInput->pData[1]->info.type;
×
7754
  SCorrRes*             pCorrRes = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
×
7755

7756
  // computing based on the true data block
7757
  SColumnInfoData* pLeft = pInput->pData[0];   // left
×
UNCOV
7758
  SColumnInfoData* pRight = pInput->pData[1];  // right
×
7759

7760
  int32_t leftMod = typeGetTypeModFromColInfo(&pLeft->info);
×
UNCOV
7761
  int32_t rightMod = typeGetTypeModFromColInfo(&pRight->info);
×
UNCOV
7762
  int32_t start = pInput->startRowIndex;
×
7763
  int32_t numOfRows = pInput->numOfRows;
×
7764

7765
  if (IS_NULL_TYPE(xType) || IS_NULL_TYPE(yType)) {
×
7766
    numOfElem = 0;
×
UNCOV
7767
    goto _over;
×
7768
  }
7769

7770
  for (int32_t i = 0; i < numOfRows; ++i) {
×
7771
    double pInputX = 0, pInputY = 0;
×
7772

UNCOV
7773
    if (colDataIsNull_f(pLeft, i) || colDataIsNull_f(pRight, i)) {
×
7774
      continue;
×
7775
    }
7776

UNCOV
7777
    char* pXVal = colDataGetData(pLeft, i);
×
UNCOV
7778
    char* pYVal = colDataGetData(pRight, i);
×
7779

UNCOV
7780
    GET_TYPED_DATA(pInputX, double, xType, pXVal, leftMod);
×
UNCOV
7781
    GET_TYPED_DATA(pInputY, double, yType, pYVal, rightMod);
×
7782

UNCOV
7783
    pCorrRes->sumLeft += pInputX;
×
UNCOV
7784
    pCorrRes->sumRight += pInputY;
×
7785

UNCOV
7786
    pCorrRes->quadLeft += pInputX * pInputX;
×
UNCOV
7787
    pCorrRes->quadRight += pInputY * pInputY;
×
7788

7789
    pCorrRes->productVal += pInputX * pInputY;
×
7790

UNCOV
7791
    pCorrRes->count += 1;
×
7792
    numOfElem += 1;
×
7793
  }
7794

UNCOV
7795
_over:
×
7796
  // data in the check operation are all null, not output
7797
  SET_VAL(GET_RES_INFO(pCtx), numOfElem, 1);
×
UNCOV
7798
  return TSDB_CODE_SUCCESS;
×
7799
}
7800

7801
int32_t corrFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
×
7802
  SInputColumnInfoData* pInput = &pCtx->input;
×
7803
  SCorrRes*             pRes = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
×
7804
  double                avg;
7805

7806
  if (pRes->count == 0) {
×
UNCOV
7807
    GET_RES_INFO(pCtx)->numOfRes = 0;
×
UNCOV
7808
    return functionFinalize(pCtx, pBlock);
×
7809
  }
7810

7811
  /**
7812
    numerator = sum_xy - (sum_x * sum_y) / n
7813
    denominator_x = math.sqrt(sum_x2 - (sum_x**2) / n)
7814
    denominator_y = math.sqrt(sum_y2 - (sum_y**2) / n)
7815

7816
    if denominator_x == 0 or denominator_y == 0:
7817
        return 0.0
7818
    res = numerator / (denominator_x * denominator_y)
7819
  */
7820

7821
  if (pRes->count == 1) {
×
7822
    pRes->result = 0.0;
×
7823
  } else {
UNCOV
7824
    double numerator = pRes->productVal - (pRes->sumLeft * pRes->sumRight) / pRes->count;
×
7825
    double dnmX = sqrt(pRes->quadLeft - pRes->sumLeft * pRes->sumLeft / pRes->count);
×
7826
    double dnmY = sqrt(pRes->quadRight - pRes->sumRight * pRes->sumRight / pRes->count);
×
7827

UNCOV
7828
    if (DBL_EQUAL(dnmX, 0.0) || DBL_EQUAL(dnmY, 0.0)) {
×
7829
      pRes->result = 0.0;
×
7830
    } else {
UNCOV
7831
      pRes->result = numerator / (dnmX * dnmY);
×
7832

7833
      if (pRes->result > 1 || pRes->result < -1) {
×
7834
        qError("invalid corr results, %.4f, numerator:%.4f, dnmX:%.4f, dnmY:%.4f", pRes->result, numerator, dnmX, dnmY);
×
7835
        if (pRes->result > 1) {
×
UNCOV
7836
          pRes->result = 1;
×
UNCOV
7837
        } else if (pRes->result < -1) {
×
7838
          pRes->result = -1;
×
7839
        }
7840
      }
7841
    }
7842
  }
7843

7844
  return functionFinalize(pCtx, pBlock);
×
7845
}
7846

UNCOV
7847
int32_t getCorrInfoSize() { return sizeof(SCorrRes); }
×
7848

7849
int32_t corrPartialFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
×
7850
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
×
UNCOV
7851
  SStdRes*             pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
×
UNCOV
7852
  int32_t              resultBytes = getCorrInfoSize();
×
7853
  char*                res = taosMemoryCalloc(resultBytes + VARSTR_HEADER_SIZE, sizeof(char));
×
7854
  int32_t              slotId = pCtx->pExpr->base.resSchema.slotId;
×
UNCOV
7855
  int32_t              code = 0;
×
7856

7857
  if (NULL == res) {
×
UNCOV
7858
    return terrno;
×
7859
  }
7860

7861
  (void)memcpy(varDataVal(res), pInfo, resultBytes);
×
UNCOV
7862
  varDataSetLen(res, resultBytes);
×
7863

7864
  SColumnInfoData* pCol = taosArrayGet(pBlock->pDataBlock, slotId);
×
7865
  if (NULL == pCol) {
×
UNCOV
7866
    taosMemoryFree(res);
×
7867
    return TSDB_CODE_OUT_OF_RANGE;
×
7868
  }
7869

UNCOV
7870
  code = colDataSetVal(pCol, pBlock->info.rows, res, false);
×
7871

7872
  taosMemoryFree(res);
×
7873
  return code;
×
7874
}
7875

7876
int32_t corrFuncMerge(SqlFunctionCtx* pCtx) {
×
7877
  SInputColumnInfoData* pInput = &pCtx->input;
×
7878
  SColumnInfoData*      pCol = pInput->pData[0];
×
7879

7880
  if (IS_NULL_TYPE(pCol->info.type)) {
×
UNCOV
7881
    SET_VAL(GET_RES_INFO(pCtx), 0, 1);
×
UNCOV
7882
    return TSDB_CODE_SUCCESS;
×
7883
  }
7884

7885
  if (pCol->info.type != TSDB_DATA_TYPE_BINARY) {
×
UNCOV
7886
    return TSDB_CODE_FUNC_FUNTION_PARA_TYPE;
×
7887
  }
7888

UNCOV
7889
  SCorrRes* pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
×
7890

UNCOV
7891
  for (int32_t i = pInput->startRowIndex; i < pInput->startRowIndex + pInput->numOfRows; ++i) {
×
UNCOV
7892
    if (colDataIsNull_s(pCol, i)) {
×
UNCOV
7893
      continue;
×
7894
    }
7895

UNCOV
7896
    char*     data = colDataGetData(pCol, i);
×
UNCOV
7897
    SCorrRes* pInputInfo = (SCorrRes*)varDataVal(data);
×
7898

UNCOV
7899
    if (pInputInfo->count == 0) {
×
UNCOV
7900
      continue;
×
7901
    }
7902

7903
    // pOutput->type = pInput->type;
UNCOV
7904
    if (pInfo->count == 0) {
×
UNCOV
7905
      TAOS_MEMCPY(pInfo, pInputInfo, sizeof(SCorrRes));
×
UNCOV
7906
    } else if (pInfo->count > 0) {
×
UNCOV
7907
      pInfo->productVal += pInputInfo->productVal;
×
UNCOV
7908
      pInfo->quadLeft += pInputInfo->quadLeft;
×
UNCOV
7909
      pInfo->quadRight += pInputInfo->quadRight;
×
UNCOV
7910
      pInfo->sumLeft += pInputInfo->sumLeft;
×
UNCOV
7911
      pInfo->sumRight += pInputInfo->sumRight;
×
UNCOV
7912
      pInfo->count += pInputInfo->count;
×
7913
    }
7914
  }
7915

UNCOV
7916
  SET_VAL(GET_RES_INFO(pCtx), pInfo->count, 1);
×
UNCOV
7917
  return TSDB_CODE_SUCCESS;
×
7918
}
7919

7920
int32_t hasNullFunction(SqlFunctionCtx* pCtx) {
14,729,140✔
7921
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
14,729,140✔
7922
  bool* pRes = GET_ROWCELL_INTERBUF(pResInfo);
14,729,140✔
7923
  if (*pRes) {
14,729,140✔
UNCOV
7924
    return TSDB_CODE_SUCCESS;
×
7925
  }
7926

7927
  SInputColumnInfoData* pInput = &pCtx->input;
14,729,140✔
7928
  SColumnDataAgg*       pAgg = pInput->pColumnDataAgg[0];
14,729,140✔
7929
  SColumnInfoData* pCol = pInput->pData[0];
14,729,140✔
7930

7931
  if (pInput->numOfRows > 0) {
14,729,140✔
7932
    pResInfo->numOfRes = 1;
14,729,140✔
7933
  }
7934

7935
  if (IS_NULL_TYPE(pCol->info.type) && pInput->numOfRows > 0) {
14,729,140✔
UNCOV
7936
    *pRes = true;
×
UNCOV
7937
    return TSDB_CODE_SUCCESS;
×
7938
  }
7939

7940
  if (pInput->colDataSMAIsSet) {
14,729,140✔
UNCOV
7941
    if (pAgg->numOfNull > 0) {
×
UNCOV
7942
      *pRes = true;
×
UNCOV
7943
      return TSDB_CODE_SUCCESS;
×
7944
    }
7945

UNCOV
7946
    if (pInput->numOfRows <= INT16_MAX) {
×
UNCOV
7947
      return TSDB_CODE_SUCCESS;
×
7948
    }
7949
  }
7950

7951
  int32_t start = pInput->startRowIndex;
14,729,140✔
7952
  int32_t end = start + pInput->numOfRows;
14,729,140✔
7953

7954
  if (pCol->hasNull) {
14,729,140✔
7955
    for (int32_t i = start; i < end; ++i) {
35,057,428✔
7956
      if (colDataIsNull_s(pCol, i)) {
59,437,168✔
7957
        *pRes = true;
9,303,810✔
7958
        break;
9,303,810✔
7959
      }
7960
    }
7961
  }  
7962

7963
  return TSDB_CODE_SUCCESS;
14,729,140✔
7964
}
7965

7966

7967

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