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

taosdata / TDengine / #4983

13 Mar 2026 03:38AM UTC coverage: 68.653% (+0.07%) from 68.587%
#4983

push

travis-ci

web-flow
feat/6641435300-save-audit-in-self (#34738)

434 of 584 new or added lines in 10 files covered. (74.32%)

434 existing lines in 121 files now uncovered.

212745 of 309883 relevant lines covered (68.65%)

134272959.11 hits per line

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

77.5
/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; }
44,481,979✔
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,994,184✔
198
  SFuncInputRowIter* pIter = &pCtx->rowIter;
53,994,184✔
199

200
  if (!pCtx->bInputFinished) {
53,994,609✔
201
    pIter->pInput = &pCtx->input;
53,994,609✔
202
    pIter->tsList = (TSKEY*)pIter->pInput->pPTS->pData;
53,994,609✔
203
    pIter->pDataCol = pIter->pInput->pData[0];
53,994,609✔
204
    pIter->pPkCol = pIter->pInput->pPrimaryKey;
53,994,609✔
205
    pIter->rowIndex = pIter->pInput->startRowIndex;
53,994,184✔
206
    pIter->inputEndIndex = pIter->rowIndex + pIter->pInput->numOfRows - 1;
53,994,184✔
207
    pIter->pSrcBlock = pCtx->pSrcBlock;
53,994,184✔
208
    if (!pIter->hasGroupId || pIter->groupId != pIter->pSrcBlock->info.id.groupId) {
53,994,184✔
209
      pIter->hasGroupId = true;
6,670,579✔
210
      pIter->groupId = pIter->pSrcBlock->info.id.groupId;
6,670,579✔
211
      pIter->hasPrev = false;
6,670,579✔
212
    }
213
  } else {
214
    pIter->finalRow = true;
×
215
  }
216
}
53,994,184✔
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,872,048✔
333
  int32_t idx = rowIndex + 1;
3,872,048✔
334
  while (idx <= pIter->inputEndIndex && pIter->tsList[idx] == pIter->tsList[rowIndex]) {
51,465,183✔
335
    ++idx;
47,593,135✔
336
  }
337
  pIter->rowIndex = idx;
3,872,048✔
338
}
3,872,048✔
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,295,710✔
351
  if (pIter->hasPrev) {
4,295,710✔
UNCOV
352
    if (pIter->prevBlockTsEnd == pIter->tsList[pIter->inputEndIndex]) {
×
353
      pIter->hasPrev = true;
×
354
      return false;
×
355
    } else {
UNCOV
356
      int32_t idx = pIter->rowIndex;
×
UNCOV
357
      while (pIter->tsList[idx] == pIter->prevBlockTsEnd) {
×
358
        ++idx;
×
359
      }
360

UNCOV
361
      pIter->hasPrev = false;
×
UNCOV
362
      setInputRowInfo(pRow, pIter, idx, true);
×
UNCOV
363
      forwardToNextDiffTsRow(pIter, idx);
×
UNCOV
364
      return true;
×
365
    }
366
  } else {
367
    if (pIter->rowIndex <= pIter->inputEndIndex) {
4,295,710✔
368
      setInputRowInfo(pRow, pIter, pIter->rowIndex, true);
4,084,308✔
369

370
      TSKEY tsEnd = pIter->tsList[pIter->inputEndIndex];
4,084,308✔
371
      if (pIter->tsList[pIter->rowIndex] != tsEnd) {
4,084,308✔
372
        forwardToNextDiffTsRow(pIter, pIter->rowIndex);
3,872,048✔
373
      } else {
374
        pIter->rowIndex = pIter->inputEndIndex + 1;
212,260✔
375
      }
376
      return true;
4,084,308✔
377
    } else {
378
      TSKEY tsEnd = pIter->tsList[pIter->inputEndIndex];
211,402✔
379
      pIter->hasPrev = true;
211,402✔
380
      pIter->prevBlockTsEnd = tsEnd;
211,402✔
381
      return false;
211,402✔
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;
54,048,583✔
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,295,710✔
400
      return funcInputGetNextRowDescPk(pIter, pRow, res);
×
401
      return TSDB_CODE_SUCCESS;
402
    } else {
403
      *res = funcInputGetNextRowAscPk(pIter, pRow);
4,295,710✔
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,295,710✔
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,137✔
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,894,611✔
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) {
81,276✔
502
  int32_t          slotId = pCtx->pExpr->base.resSchema.slotId;
81,276✔
503
  SColumnInfoData* pCol = taosArrayGet(pBlock->pDataBlock, slotId);
81,276✔
504
  if (NULL == pCol) {
81,276✔
505
    return TSDB_CODE_OUT_OF_RANGE;
×
506
  }
507
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
81,276✔
508
  pResInfo->isNullRes = (pResInfo->numOfRes == 0) ? 1 : 0;
81,276✔
509

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

513
  return code;
81,276✔
514
}
515

516
EFuncDataRequired countDataRequired(SFunctionNode* pFunc, STimeWindow* pTimeWindow) {
14,034,339✔
517
  SNode* pParam = nodesListGetNode(pFunc->pParameterList, 0);
14,034,339✔
518
  if (QUERY_NODE_COLUMN == nodeType(pParam) && PRIMARYKEY_TIMESTAMP_COL_ID == ((SColumnNode*)pParam)->colId) {
14,036,127✔
519
    return FUNC_DATA_REQUIRED_NOT_LOAD;
10,196,643✔
520
  }
521
  return FUNC_DATA_REQUIRED_SMA_LOAD;
3,839,255✔
522
}
523

524
bool getCountFuncEnv(SFunctionNode* UNUSED_PARAM(pFunc), SFuncExecEnv* pEnv) {
51,097,136✔
525
  pEnv->calcMemSize = sizeof(int64_t);
51,097,136✔
526
  return true;
51,120,167✔
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,852,302✔
541
  }
542
  if (pInput->colDataSMAIsSet && pInput->totalRows == pInput->numOfRows) {
2,147,483,647✔
543
    numOfElem = pInput->numOfRows - pInput->pColumnDataAgg[0]->numOfNull;
800,893✔
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;
1,558,888,870✔
578
    val += 0;
1,558,888,870✔
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,875,759✔
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,090,147,930✔
620
    goto _sum_over;
1,090,147,930✔
621
  }
622

623
  if (pInput->colDataSMAIsSet) {
2,147,483,647✔
624
    numOfElem = pInput->numOfRows - pAgg->numOfNull;
29,720,802✔
625

626
    if (IS_SIGNED_NUMERIC_TYPE(type)) {
29,720,802✔
627
      SUM_RES_INC_ISUM(pSumRes, pAgg->sum);
15,165,282✔
628
    } else if (IS_UNSIGNED_NUMERIC_TYPE(type)) {
14,555,520✔
629
      SUM_RES_INC_USUM(pSumRes, pAgg->sum);
14,550,475✔
630
    } else if (IS_FLOAT_TYPE(type)) {
5,045✔
631
      SUM_RES_INC_DSUM(pSumRes, GET_DOUBLE_VAL((const char*)&(pAgg->sum)));
×
632
    } else if (IS_DECIMAL_TYPE(type)) {
8,030✔
633
      SUM_RES_SET_TYPE(pSumRes, pCtx->inputType, TSDB_DATA_TYPE_DECIMAL);
8,030✔
634
      const SDecimalOps* pOps = getDecimalOps(TSDB_DATA_TYPE_DECIMAL);
8,030✔
635
      if (pAgg->overflow || decimal128AddCheckOverflow((Decimal*)&SUM_RES_GET_DECIMAL_SUM(pSumRes),
14,600✔
636
                                                       &pAgg->decimal128Sum, DECIMAL_WORD_NUM(Decimal))) {
6,570✔
637
        return TSDB_CODE_DECIMAL_OVERFLOW;
1,460✔
638
      }
639
      pOps->add(&SUM_RES_GET_DECIMAL_SUM(pSumRes), &pAgg->decimal128Sum, DECIMAL_WORD_NUM(Decimal));
6,570✔
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,225,505,754✔
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,739,194✔
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,151,310✔
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) {
195,527,141✔
668
      LIST_ADD_N(SUM_RES_GET_DSUM(pSumRes), pCol, start, numOfRows, double, numOfElem);
461,704,784✔
669
    } else if (type == TSDB_DATA_TYPE_FLOAT) {
137,203,345✔
670
      LIST_ADD_N(SUM_RES_GET_DSUM(pSumRes), pCol, start, numOfRows, float, numOfElem);
453,047,060✔
671
    } else if (IS_DECIMAL_TYPE(type)) {
34,434✔
672
      SUM_RES_SET_TYPE(pSumRes, pCtx->inputType, TSDB_DATA_TYPE_DECIMAL);
34,434✔
673
      int32_t overflow = false;
21,900✔
674
      if (TSDB_DATA_TYPE_DECIMAL64 == type) {
21,900✔
675
        LIST_ADD_DECIMAL_N(&SUM_RES_GET_DECIMAL_SUM(pSumRes), pCol, start, numOfRows, Decimal64, numOfElem);
5,845,840✔
676
      } else if (TSDB_DATA_TYPE_DECIMAL == type) {
16,060✔
677
        LIST_ADD_DECIMAL_N(&SUM_RES_GET_DECIMAL_SUM(pSumRes), pCol, start, numOfRows, Decimal128, numOfElem);
11,700,440✔
678
      }
679
      if (overflow) return TSDB_CODE_DECIMAL_OVERFLOW;
21,900✔
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)) {
108,994,894✔
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) {
28,065,014✔
725
  pEnv->calcMemSize = SUM_RES_GET_SIZE(pFunc->node.resType.type);
28,065,014✔
726
  return true;
28,068,588✔
727
}
728

729
static bool funcNotSupportStringSma(SFunctionNode* pFunc) {
21,481,404✔
730
  SNode* pParam;
731
  switch (pFunc->funcType) {
21,481,404✔
732
    case FUNCTION_TYPE_MAX:
21,479,652✔
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);
21,479,652✔
744
      if (pParam && nodesIsExprNode(pParam) && (IS_VAR_DATA_TYPE(((SExprNode*)pParam)->resType.type))) {
21,481,049✔
745
        return true;
1,135,222✔
746
      }
747
      break;
20,345,580✔
748
    default:
1,752✔
749
      break;
1,752✔
750
  }
751
  return false;
20,347,332✔
752
}
753

754
EFuncDataRequired statisDataRequired(SFunctionNode* pFunc, STimeWindow* pTimeWindow) {
21,477,686✔
755
  if (funcNotSupportStringSma(pFunc)) {
21,477,686✔
756
    return FUNC_DATA_REQUIRED_DATA_LOAD;
1,135,222✔
757
  }
758
  return FUNC_DATA_REQUIRED_SMA_LOAD;
20,346,111✔
759
}
760

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

769
  SMinmaxResInfo* buf = GET_ROWCELL_INTERBUF(pResultInfo);
2,018,376,201✔
770
  buf->assign = false;
2,018,536,351✔
771
  buf->tuplePos.pageId = -1;
2,018,539,381✔
772

773
  buf->nullTupleSaved = false;
2,018,528,056✔
774
  buf->nullTuplePos.pageId = -1;
2,018,543,502✔
775
  buf->str = NULL;
2,018,531,755✔
776
  return TSDB_CODE_SUCCESS;
2,018,536,075✔
777
}
778

779
bool getMinmaxFuncEnv(SFunctionNode* UNUSED_PARAM(pFunc), SFuncExecEnv* pEnv) {
50,873,335✔
780
  COMPILE_TIME_ASSERT(sizeof(SMinmaxResInfo) == sizeof(SOldMinMaxResInfo));
781
  pEnv->calcMemSize = sizeof(SMinmaxResInfo);
50,873,335✔
782
  return true;
50,873,166✔
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) {
1,987,039,192✔
810
  int32_t code = TSDB_CODE_SUCCESS;
1,987,039,192✔
811

812
  SResultRowEntryInfo* pEntryInfo = GET_RES_INFO(pCtx);
1,987,039,192✔
813
  SMinmaxResInfo*      pRes = GET_ROWCELL_INTERBUF(pEntryInfo);
1,987,041,452✔
814

815
  int32_t slotId = pCtx->pExpr->base.resSchema.slotId;
1,987,041,452✔
816
  int32_t currentRow = pBlock->info.rows;
1,987,041,452✔
817

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

824
  // NOTE: do nothing change it, for performance issue
825
  if (!pEntryInfo->isNullRes) {
1,987,039,265✔
826
    switch (pCol->info.type) {
1,539,115,841✔
827
      case TSDB_DATA_TYPE_UBIGINT:
137,132,810✔
828
      case TSDB_DATA_TYPE_BIGINT:
829
      case TSDB_DATA_TYPE_TIMESTAMP:
830
        ((int64_t*)pCol->pData)[currentRow] = pRes->v;
137,132,810✔
831
        break;
137,131,694✔
832
      case TSDB_DATA_TYPE_UINT:
1,281,332,329✔
833
      case TSDB_DATA_TYPE_INT:
834
        colDataSetInt32(pCol, currentRow, (int32_t*)&pRes->v);
1,281,332,329✔
835
        break;
1,281,331,410✔
836
      case TSDB_DATA_TYPE_USMALLINT:
15,143,077✔
837
      case TSDB_DATA_TYPE_SMALLINT:
838
        colDataSetInt16(pCol, currentRow, (int16_t*)&pRes->v);
15,143,077✔
839
        break;
15,143,077✔
840
      case TSDB_DATA_TYPE_BOOL:
38,657,090✔
841
      case TSDB_DATA_TYPE_UTINYINT:
842
      case TSDB_DATA_TYPE_TINYINT:
843
        colDataSetInt8(pCol, currentRow, (int8_t*)&pRes->v);
38,657,090✔
844
        break;
38,657,090✔
845
      case TSDB_DATA_TYPE_DOUBLE:
29,127,177✔
846
        colDataSetDouble(pCol, currentRow, (double*)&pRes->v);
29,127,177✔
847
        break;
29,127,177✔
848
      case TSDB_DATA_TYPE_FLOAT: {
29,087,087✔
849
        float v = GET_FLOAT_VAL(&pRes->v);
29,087,087✔
850
        colDataSetFloat(pCol, currentRow, &v);
29,087,087✔
851
        break;
29,087,087✔
852
      }
853
      case TSDB_DATA_TYPE_VARBINARY:
7,978,243✔
854
      case TSDB_DATA_TYPE_VARCHAR:
855
      case TSDB_DATA_TYPE_NCHAR: {
856
        code = colDataSetVal(pCol, currentRow, pRes->str, false);
7,978,243✔
857
        if (TSDB_CODE_SUCCESS != code) {
7,978,664✔
858
          return code;
×
859
        }
860
        break;
7,978,664✔
861
      }
862
      case TSDB_DATA_TYPE_DECIMAL64:
627,817✔
863
        code = colDataSetVal(pCol, currentRow, (const char*)&pRes->v, false);
627,817✔
864
        break;
627,817✔
865
      case TSDB_DATA_TYPE_DECIMAL:
30,285✔
866
        code = colDataSetVal(pCol, currentRow, (void*)pRes->dec, false);
30,285✔
867
        break;
30,285✔
868
    }
869
  } else {
870
    colDataSetNULL(pCol, currentRow);
447,923,074✔
871
  }
872

873
  if (IS_VAR_DATA_TYPE(pCol->info.type)) taosMemoryFreeClear(pRes->str);
1,987,035,693✔
874
  if (pCtx->subsidiaries.num > 0) {
1,987,041,873✔
875
    if (pEntryInfo->numOfRes > 0) {
2,079,242✔
876
      code = setSelectivityValue(pCtx, pBlock, &pRes->tuplePos, currentRow);
1,837,240✔
877
    } else {
878
      code = setNullSelectivityValue(pCtx, pBlock, currentRow);
242,002✔
879
    }
880
  }
881

882
  return code;
1,987,039,310✔
883
}
884

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

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

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

901
  return TSDB_CODE_SUCCESS;
314,423✔
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) ||
71,316,505✔
910
      (pCtx->saveHandle.pState && pTuplePos->streamTupleKey.ts > 0)) {
421✔
911
    int32_t numOfCols = pCtx->subsidiaries.num;
71,317,819✔
912
    char*   p = NULL;
71,315,848✔
913
    int32_t code = loadTupleData(pCtx, pTuplePos, &p);
71,317,819✔
914
    if (p == NULL || TSDB_CODE_SUCCESS != code) {
71,315,427✔
915
      qError("Load tuple data failed since %s, groupId:%" PRIu64 ", ts:%" PRId64, terrstr(),
421✔
916
             pTuplePos->streamTupleKey.groupId, pTuplePos->streamTupleKey.ts);
917
      return TSDB_CODE_NOT_FOUND;
×
918
    }
919

920
    bool* nullList = (bool*)p;
71,315,006✔
921
    char* pStart = (char*)(nullList + numOfCols * sizeof(bool));
71,315,006✔
922

923
    // todo set the offset value to optimize the performance.
924
    for (int32_t j = 0; j < numOfCols; ++j) {
234,149,409✔
925
      SqlFunctionCtx* pc = pCtx->subsidiaries.pCtx[j];
162,833,561✔
926
      int32_t         dstSlotId = pc->pExpr->base.resSchema.slotId;
162,833,797✔
927

928
      SColumnInfoData* pDstCol = taosArrayGet(pBlock->pDataBlock, dstSlotId);
162,834,033✔
929
      if (NULL == pDstCol) {
162,834,875✔
930
        return terrno;
×
931
      }
932
      if (nullList[j]) {
162,834,875✔
933
        colDataSetNULL(pDstCol, rowIndex);
52,669,029✔
934
      } else {
935
        code = colDataSetValOrCover(pDstCol, rowIndex, pStart, false);
110,163,690✔
936
        if (TSDB_CODE_SUCCESS != code) {
110,165,189✔
937
          return code;
×
938
        }
939
      }
940
      pStart += pDstCol->info.bytes;
162,834,218✔
941
    }
942
  }
943

944
  return TSDB_CODE_SUCCESS;
71,317,162✔
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) {
980,564✔
950
  if (pCtx->subsidiaries.num <= 0) {
980,564✔
951
    return TSDB_CODE_SUCCESS;
×
952
  }
953

954
  int32_t code = TSDB_CODE_SUCCESS;
980,564✔
955
  for (int32_t j = 0; j < pCtx->subsidiaries.num; ++j) {
2,221,060✔
956
    SqlFunctionCtx* pc = pCtx->subsidiaries.pCtx[j];
1,240,496✔
957

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

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

967
    char* pData = colDataGetData(pSrcCol, rowIndex);
1,240,496✔
968

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

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

977
    if (colDataIsNull_s(pSrcCol, rowIndex) == true) {
2,480,992✔
978
      colDataSetNULL(pDstCol, pos);
51,472✔
979
    } else {
980
      code = colDataSetVal(pDstCol, pos, pData, false);
1,189,024✔
981
      if (TSDB_CODE_SUCCESS != code) {
1,189,024✔
982
        return code;
×
983
      }
984
    }
985
  }
986
  return code;
980,564✔
987
}
988

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);
×
994
  SMinmaxResInfo*      pDBuf = GET_ROWCELL_INTERBUF(pDResInfo);
×
995

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

1000
  switch (type) {
×
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;
×
1006
        replaceTupleData(&pDBuf->tuplePos, &pSBuf->tuplePos);
×
1007
        pDBuf->assign = true;
×
1008
      }
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;
×
1014
        replaceTupleData(&pDBuf->tuplePos, &pSBuf->tuplePos);
×
1015
        pDBuf->assign = true;
×
1016
      }
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;
×
1022
        replaceTupleData(&pDBuf->tuplePos, &pSBuf->tuplePos);
×
1023
        pDBuf->assign = true;
×
1024
      }
1025
      break;
×
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;
×
1031
        replaceTupleData(&pDBuf->tuplePos, &pSBuf->tuplePos);
×
1032
        pDBuf->assign = true;
×
1033
      }
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;
×
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;
×
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);
×
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));
×
1065
        replaceTupleData(&pDBuf->tuplePos, &pSBuf->tuplePos);
×
1066
        pDBuf->assign = true;
×
1067
      }
1068
      break;
×
1069
  }
1070
  pDResInfo->numOfRes = TMAX(pDResInfo->numOfRes, pSResInfo->numOfRes);
×
1071
  pDResInfo->isNullRes &= pSResInfo->isNullRes;
×
1072
  return TSDB_CODE_SUCCESS;
×
1073
}
1074

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

1082
int32_t getStdInfoSize() { return (int32_t)sizeof(SStdRes); }
18,206,297✔
1083

1084
bool getStdFuncEnv(SFunctionNode* pFunc, SFuncExecEnv* pEnv) {
4,628,869✔
1085
  pEnv->calcMemSize = sizeof(SStdRes);
4,628,869✔
1086
  return true;
4,629,907✔
1087
}
1088

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

1097
  SStdRes* pRes = GET_ROWCELL_INTERBUF(pResultInfo);
566,134,387✔
1098
  (void)memset(pRes, 0, sizeof(SStdRes));
566,134,473✔
1099
  return TSDB_CODE_SUCCESS;
566,134,473✔
1100
}
1101

1102
int32_t stdFunction(SqlFunctionCtx* pCtx) {
1,075,477,460✔
1103
  int32_t numOfElem = 0;
1,075,477,460✔
1104

1105
  // Only the pre-computing information loaded and actual data does not loaded
1106
  SInputColumnInfoData* pInput = &pCtx->input;
1,075,477,460✔
1107
  int32_t               type = pInput->pData[0]->info.type;
1,075,486,690✔
1108

1109
  SStdRes* pStdRes = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
1,075,490,451✔
1110
  pStdRes->type = type;
1,075,492,988✔
1111

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

1115
  int32_t start = pInput->startRowIndex;
1,075,482,303✔
1116
  int32_t numOfRows = pInput->numOfRows;
1,075,476,287✔
1117

1118
  if (IS_NULL_TYPE(type)) {
1,075,482,228✔
1119
    numOfElem = 0;
164,158,045✔
1120
    goto _stddev_over;
164,158,045✔
1121
  }
1122

1123
  switch (type) {
911,324,183✔
1124
    case TSDB_DATA_TYPE_TINYINT: {
12,552,914✔
1125
      int8_t* plist = (int8_t*)pCol->pData;
12,552,914✔
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,619,732,765✔
1132
        pStdRes->count += 1;
1,619,732,765✔
1133
        double nr = (double)plist[i];
1,628,433,566✔
1134
        if (pStdRes->count == 1) {
1,628,455,074✔
1135
          pStdRes->dsum = nr;
750,860✔
1136
        } else {
1137
          double          s_kminusone = pStdRes->dsum;
1,627,766,854✔
1138
          volatile double diff = nr - s_kminusone;
1,627,729,828✔
1139
          pStdRes->dsum = s_kminusone + diff / (double)pStdRes->count;
1,627,729,828✔
1140
          pStdRes->quadraticDSum += diff * (nr - pStdRes->dsum);
1,627,809,313✔
1141
        }
1142
      }
1143

1144
      break;
12,440,027✔
1145
    }
1146

1147
    case TSDB_DATA_TYPE_SMALLINT: {
769,906,274✔
1148
      int16_t* plist = (int16_t*)pCol->pData;
769,906,274✔
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,100,596,502✔
1155
        pStdRes->count += 1;
2,100,596,502✔
1156
        double nr = (double)plist[i];
2,114,864,579✔
1157
        if (pStdRes->count == 1) {
2,114,873,460✔
1158
          pStdRes->dsum = nr;
348,365,156✔
1159
        } else {
1160
          double          s_kminusone = pStdRes->dsum;
1,766,512,631✔
1161
          volatile double diff = nr - s_kminusone;
1,766,486,506✔
1162
          pStdRes->dsum = s_kminusone + diff / (double)pStdRes->count;
1,766,486,506✔
1163
          pStdRes->quadraticDSum += diff * (nr - pStdRes->dsum);
1,766,477,408✔
1164
        }
1165
      }
1166
      break;
769,906,009✔
1167
    }
1168

1169
    case TSDB_DATA_TYPE_INT: {
16,956,465✔
1170
      int32_t* plist = (int32_t*)pCol->pData;
16,956,465✔
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,942,177,001✔
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;
9,665,812✔
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;
16,955,249✔
1190
    }
1191

1192
    case TSDB_DATA_TYPE_BIGINT: {
19,553,065✔
1193
      int64_t* plist = (int64_t*)pCol->pData;
19,553,065✔
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,047,403,614✔
1200
        pStdRes->count += 1;
2,047,403,614✔
1201
        double nr = (double)plist[i];
2,060,151,428✔
1202
        if (pStdRes->count == 1) {
2,060,197,534✔
1203
          pStdRes->dsum = nr;
8,174,049✔
1204
        } else {
1205
          double          s_kminusone = pStdRes->dsum;
2,052,110,148✔
1206
          volatile double diff = nr - s_kminusone;
2,051,992,263✔
1207
          pStdRes->dsum = s_kminusone + diff / (double)pStdRes->count;
2,051,992,263✔
1208
          pStdRes->quadraticDSum += diff * (nr - pStdRes->dsum);
2,052,158,845✔
1209
        }
1210
      }
1211
      break;
19,554,097✔
1212
    }
1213

1214
    case TSDB_DATA_TYPE_UTINYINT: {
13,631,393✔
1215
      uint8_t* plist = (uint8_t*)pCol->pData;
13,631,393✔
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;
204,929✔
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,867,684✔
1235
    }
1236

1237
    case TSDB_DATA_TYPE_USMALLINT: {
10,958,200✔
1238
      uint16_t* plist = (uint16_t*)pCol->pData;
10,958,200✔
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,387,392,962✔
1245
        pStdRes->count += 1;
1,387,392,962✔
1246
        double nr = (double)plist[i];
1,399,275,144✔
1247
        if (pStdRes->count == 1) {
1,399,273,950✔
1248
          pStdRes->dsum = nr;
89,048✔
1249
        } else {
1250
          double          s_kminusone = pStdRes->dsum;
1,399,183,111✔
1251
          volatile double diff = nr - s_kminusone;
1,399,183,111✔
1252
          pStdRes->dsum = s_kminusone + diff / (double)pStdRes->count;
1,399,183,111✔
1253
          pStdRes->quadraticDSum += diff * (nr - pStdRes->dsum);
1,399,180,126✔
1254
        }
1255
      }
1256
      break;
10,957,603✔
1257
    }
1258

1259
    case TSDB_DATA_TYPE_UINT: {
5,975,715✔
1260
      uint32_t* plist = (uint32_t*)pCol->pData;
5,975,715✔
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,075,780,993✔
1264
        }
1265

1266
        numOfElem += 1;
843,735,212✔
1267
        pStdRes->count += 1;
843,735,212✔
1268
        double nr = (double)plist[i];
847,893,585✔
1269
        if (pStdRes->count == 1) {
848,005,895✔
1270
          pStdRes->dsum = nr;
60,024✔
1271
        } else {
1272
          double          s_kminusone = pStdRes->dsum;
847,947,662✔
1273
          volatile double diff = nr - s_kminusone;
847,927,734✔
1274
          pStdRes->dsum = s_kminusone + diff / (double)pStdRes->count;
847,927,734✔
1275
          pStdRes->quadraticDSum += diff * (nr - pStdRes->dsum);
847,939,452✔
1276
        }
1277
      }
1278

1279
      break;
5,976,312✔
1280
    }
1281

1282
    case TSDB_DATA_TYPE_UBIGINT: {
5,975,948✔
1283
      uint64_t* plist = (uint64_t*)pCol->pData;
5,975,948✔
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;
660,648,918✔
1290
        pStdRes->count += 1;
660,648,918✔
1291
        double nr = (double)plist[i];
664,051,544✔
1292
        if (pStdRes->count == 1) {
664,057,177✔
1293
          pStdRes->dsum = nr;
51,774✔
1294
        } else {
1295
          double          s_kminusone = pStdRes->dsum;
664,017,820✔
1296
          volatile double diff = nr - s_kminusone;
663,938,434✔
1297
          pStdRes->dsum = s_kminusone + diff / (double)pStdRes->count;
663,938,434✔
1298
          pStdRes->quadraticDSum += diff * (nr - pStdRes->dsum);
663,876,786✔
1299
        }
1300
      }
1301
      break;
5,974,732✔
1302
    }
1303

1304
    case TSDB_DATA_TYPE_FLOAT: {
9,603,195✔
1305
      float* plist = (float*)pCol->pData;
9,603,195✔
1306
      for (int32_t i = start; i < numOfRows + pInput->startRowIndex; ++i) {
1,748,156,205✔
1307
        if (pCol->hasNull && colDataIsNull_f(pCol, i)) {
1,738,552,894✔
1308
          continue;
2,269,761✔
1309
        }
1310

1311
        numOfElem += 1;
1,736,281,303✔
1312
        pStdRes->count += 1;
1,736,281,303✔
1313
        double nr = (double)plist[i];
1,736,282,914✔
1314
        if (pStdRes->count == 1) {
1,736,282,798✔
1315
          pStdRes->dsum = nr;
8,187,140✔
1316
        } else {
1317
          double          s_kminusone = pStdRes->dsum;
1,728,095,542✔
1318
          volatile double diff = nr - s_kminusone;
1,728,095,194✔
1319
          pStdRes->dsum = s_kminusone + diff / (double)pStdRes->count;
1,728,095,194✔
1320
          pStdRes->quadraticDSum += diff * (nr - pStdRes->dsum);
1,728,095,877✔
1321
        }
1322
      }
1323
      break;
9,603,646✔
1324
    }
1325

1326
    case TSDB_DATA_TYPE_DOUBLE: {
46,211,014✔
1327
      double* plist = (double*)pCol->pData;
46,211,014✔
1328
      for (int32_t i = start; i < numOfRows + pInput->startRowIndex; ++i) {
357,084,390✔
1329
        if (pCol->hasNull && colDataIsNull_f(pCol, i)) {
310,891,034✔
1330
          continue;
114,115,511✔
1331
        }
1332

1333
        numOfElem += 1;
196,753,695✔
1334
        pStdRes->count += 1;
196,753,695✔
1335
        double nr = (double)plist[i];
196,739,559✔
1336
        if (pStdRes->count == 1) {
196,740,603✔
1337
          pStdRes->dsum = nr;
23,107,086✔
1338
        } else {
1339
          double          s_kminusone = pStdRes->dsum;
173,637,153✔
1340
          volatile double diff = nr - s_kminusone;
173,620,461✔
1341
          pStdRes->dsum = s_kminusone + diff / (double)pStdRes->count;
173,620,461✔
1342
          pStdRes->quadraticDSum += diff * (nr - pStdRes->dsum);
173,643,945✔
1343
        }
1344
      }
1345
      break;
46,214,128✔
1346
    }
1347

1348
    default:
×
1349
      break;
×
1350
  }
1351

1352
_stddev_over:
1,076,607,532✔
1353
  // data in the check operation are all null, not output
1354
  SET_VAL(GET_RES_INFO(pCtx), numOfElem, 1);
1,076,607,532✔
1355
  return TSDB_CODE_SUCCESS;
1,075,477,809✔
1356
}
1357

1358
static void stdTransferInfo(SStdRes* pInput, SStdRes* pOutput) {
17,695,328✔
1359
  if (IS_NULL_TYPE(pInput->type)) {
17,695,328✔
1360
    return;
21,625✔
1361
  }
1362
  pOutput->type = pInput->type;
17,673,703✔
1363
  if (pOutput->count == 0) {
17,673,703✔
1364
    pOutput->quadraticDSum += pInput->quadraticDSum;
17,016,924✔
1365
    pOutput->dsum += pInput->dsum;
17,016,924✔
1366
    pOutput->count = pInput->count;
17,016,924✔
1367
  } else if (pInput->count > 0) {
656,779✔
1368
    double totalCount = pOutput->count + pInput->count;
257,019✔
1369
    double totalSum = pInput->count * pInput->dsum + pOutput->count * pOutput->dsum;
257,019✔
1370
    double mean = totalSum / totalCount;
257,019✔
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;
257,019✔
1378
    pOutput->quadraticDSum += pInput->quadraticDSum + pInput->count * pOutput->count * (diff * diff) / totalCount;
257,019✔
1379
    pOutput->dsum = mean;
257,019✔
1380
    pOutput->count += pInput->count;
257,019✔
1381
  }
1382
}
1383

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

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

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

1397
  SStdRes* pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
17,683,892✔
1398

1399
  for (int32_t i = pInput->startRowIndex; i < pInput->startRowIndex + pInput->numOfRows; ++i) {
35,379,220✔
1400
    if (colDataIsNull_s(pCol, i)) continue;
35,390,656✔
1401
    char*    data = colDataGetData(pCol, i);
17,695,328✔
1402
    SStdRes* pInputInfo = (SStdRes*)varDataVal(data);
17,695,328✔
1403
    stdTransferInfo(pInputInfo, pInfo);
17,695,328✔
1404
  }
1405

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

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

1416
  if (pStddevRes->count == 0) {
525,972,574✔
1417
    GET_RES_INFO(pCtx)->numOfRes = 0;
148,797,593✔
1418

1419
    return functionFinalize(pCtx, pBlock);
148,797,593✔
1420
  }
1421

1422
  if (pStddevRes->count == 1) {
377,174,981✔
1423
    pStddevRes->result = 0.0;
261,580,707✔
1424
  } else {
1425
    pStddevRes->result = sqrt(pStddevRes->quadraticDSum / pStddevRes->count);
115,594,274✔
1426
  }
1427

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

1433
  return functionFinalize(pCtx, pBlock);
377,174,981✔
1434
}
1435

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

1442
  if (pStdvarRes->count == 0) {
6,585,428✔
1443
    GET_RES_INFO(pCtx)->numOfRes = 0;
24,012✔
1444
    return functionFinalize(pCtx, pBlock);
24,012✔
1445
  }
1446

1447
  if (pStdvarRes->count == 1) {
6,561,416✔
1448
    pStdvarRes->result = 0.0;
906✔
1449
  } else {
1450
    pStdvarRes->result = pStdvarRes->quadraticDSum / pStdvarRes->count;
6,560,510✔
1451
  }
1452

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

1458
  return functionFinalize(pCtx, pBlock);
6,561,416✔
1459
}
1460

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

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

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

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

1482
  taosMemoryFree(res);
17,698,449✔
1483
  return code;
17,698,808✔
1484
}
1485

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

1490
  SResultRowEntryInfo* pSResInfo = GET_RES_INFO(pSourceCtx);
×
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);
×
1497
  pDResInfo->isNullRes &= pSResInfo->isNullRes;
×
1498
  return TSDB_CODE_SUCCESS;
×
1499
}
1500

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

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

1511
  if (pStddevRes->count == 1) {
3,159,687✔
1512
    pStddevRes->result = 0.0;
453✔
1513
  } else {
1514
    pStddevRes->result = sqrt(pStddevRes->quadraticDSum / (pStddevRes->count - 1));
3,159,234✔
1515
  }
1516

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

1522
  return functionFinalize(pCtx, pBlock);
3,159,687✔
1523
}
1524

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

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

1535
  if (pStddevRes->count == 1) {
3,158,781✔
1536
    pStddevRes->result = 0.0;
453✔
1537
  } else {
1538
    pStddevRes->result = pStddevRes->quadraticDSum / (pStddevRes->count - 1);
3,158,328✔
1539
  }
1540

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

1546
  return functionFinalize(pCtx, pBlock);
3,158,781✔
1547
}
1548

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

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

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

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

1567
  int32_t sepParamIdx = pCtx->numOfParams - 1;
1,405✔
1568
  pRes->separator = pCtx->param[sepParamIdx].param.pz;
1,405✔
1569
  pRes->type = pCtx->param[sepParamIdx].param.nType;
1,405✔
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,405✔
1579
}
1580

1581
static int32_t gconcatHelper(const char* input, char* output, bool hasNchar, int32_t type, VarDataLenT* dataLen,
17,765✔
1582
                             void* charsetCxt) {
1583
  if (hasNchar && type == TSDB_DATA_TYPE_VARCHAR) {
17,765✔
1584
    TdUcs4* newBuf = taosMemoryCalloc((varDataLen(input) + 1) * TSDB_NCHAR_SIZE, 1);
×
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) {
×
1592
      taosMemoryFree(newBuf);
×
1593
      return TSDB_CODE_SCALAR_CONVERT_ERROR;
×
1594
    }
1595
    (void)memcpy(varDataVal(output) + *dataLen, newBuf, len);
×
1596
    *dataLen += len;
×
1597
    taosMemoryFree(newBuf);
×
1598
  } else {
1599
    (void)memcpy(varDataVal(output) + *dataLen, varDataVal(input), varDataLen(input));
17,765✔
1600
    *dataLen += varDataLen(input);
17,765✔
1601
  }
1602

1603
  return TSDB_CODE_SUCCESS;
17,765✔
1604
}
1605

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

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

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

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

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

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;
935✔
1648
  SColumnInfoData* pCol = pInput->pData[numOfCols - 1];
935✔
1649

1650
  sep = colDataGetData(pCol, 0);
935✔
1651
  pRes->type = pCol->info.type;
935✔
1652
  for (int r = rowStart; r < rowStart + numOfRows; ++r) {
10,285✔
1653
    if (prefixSep) {
9,350✔
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,415✔
1658
      if (code) {
8,415✔
1659
        goto _over;
×
1660
      }
1661
    }
1662

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

1667
      if (IS_NULL_TYPE(type) || (pCol->hasNull && colDataIsNull_f(pCol, r))) {
9,350✔
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,350✔
1673
      if (code) {
9,350✔
1674
        goto _over;
×
1675
      }
1676
    }
1677

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

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

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

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

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

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

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

1706
  return code;
935✔
1707
}
1708

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

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

1722
  SLeastSQRInfo* pInfo = GET_ROWCELL_INTERBUF(pResultInfo);
4,393,861✔
1723

1724
  GET_TYPED_DATA(pInfo->startVal, double, pCtx->param[1].param.nType, &pCtx->param[1].param.i,
4,393,861✔
1725
                 typeGetTypeModFromCol(pCtx->param[1].pCol));
1726
  GET_TYPED_DATA(pInfo->stepVal, double, pCtx->param[2].param.nType, &pCtx->param[2].param.i,
4,394,383✔
1727
                 typeGetTypeModFromCol(pCtx->param[2].pCol));
1728
  return TSDB_CODE_SUCCESS;
4,394,383✔
1729
}
1730

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

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

1737
  SLeastSQRInfo* pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
5,210,230✔
1738

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

1741
  double(*param)[3] = pInfo->matrix;
5,210,230✔
1742
  double x = pInfo->startVal;
5,210,230✔
1743

1744
  int32_t start = pInput->startRowIndex;
5,210,230✔
1745
  int32_t numOfRows = pInput->numOfRows;
5,209,779✔
1746

1747
  switch (type) {
5,210,230✔
1748
    case TSDB_DATA_TYPE_TINYINT: {
798,884✔
1749
      int8_t* plist = (int8_t*)pCol->pData;
798,884✔
1750
      for (int32_t i = start; i < numOfRows + pInput->startRowIndex; ++i) {
90,230,056✔
1751
        if (pCol->hasNull && colDataIsNull_f(pCol, i)) {
89,429,606✔
1752
          continue;
157,236✔
1753
        }
1754
        numOfElem++;
89,271,848✔
1755
        LEASTSQR_CAL(param, x, plist, i, pInfo->stepVal);
89,271,848✔
1756
      }
1757
      break;
798,884✔
1758
    }
1759
    case TSDB_DATA_TYPE_SMALLINT: {
2,767,098✔
1760
      int16_t* plist = (int16_t*)pCol->pData;
2,767,098✔
1761
      for (int32_t i = start; i < numOfRows + pInput->startRowIndex; ++i) {
96,963,830✔
1762
        if (pCol->hasNull && colDataIsNull_f(pCol, i)) {
94,196,732✔
1763
          continue;
76,411,116✔
1764
        }
1765

1766
        numOfElem++;
17,785,616✔
1767
        LEASTSQR_CAL(param, x, plist, i, pInfo->stepVal);
17,785,616✔
1768
      }
1769
      break;
2,767,098✔
1770
    }
1771

1772
    case TSDB_DATA_TYPE_INT: {
410,810✔
1773
      int32_t* plist = (int32_t*)pCol->pData;
410,810✔
1774
      for (int32_t i = start; i < numOfRows + pInput->startRowIndex; ++i) {
87,642,938✔
1775
        if (pCol->hasNull && colDataIsNull_f(pCol, i)) {
87,232,128✔
1776
          continue;
334,470✔
1777
        }
1778

1779
        numOfElem++;
86,897,207✔
1780
        LEASTSQR_CAL(param, x, plist, i, pInfo->stepVal);
86,897,207✔
1781
      }
1782
      break;
410,810✔
1783
    }
1784

1785
    case TSDB_DATA_TYPE_BIGINT: {
69,518✔
1786
      int64_t* plist = (int64_t*)pCol->pData;
69,518✔
1787
      for (int32_t i = start; i < numOfRows + pInput->startRowIndex; ++i) {
17,916,322✔
1788
        if (pCol->hasNull && colDataIsNull_f(pCol, i)) {
17,846,804✔
1789
          continue;
56,436✔
1790
        }
1791

1792
        numOfElem++;
17,790,368✔
1793
        LEASTSQR_CAL(param, x, plist, i, pInfo->stepVal);
17,790,368✔
1794
      }
1795
      break;
69,518✔
1796
    }
1797

1798
    case TSDB_DATA_TYPE_UTINYINT: {
17,058✔
1799
      uint8_t* plist = (uint8_t*)pCol->pData;
17,058✔
1800
      for (int32_t i = start; i < numOfRows + pInput->startRowIndex; ++i) {
17,655,110✔
1801
        if (pCol->hasNull && colDataIsNull_f(pCol, i)) {
17,638,052✔
1802
          continue;
9,966✔
1803
        }
1804
        numOfElem++;
17,628,086✔
1805
        LEASTSQR_CAL(param, x, plist, i, pInfo->stepVal);
17,628,086✔
1806
      }
1807
      break;
17,058✔
1808
    }
1809
    case TSDB_DATA_TYPE_USMALLINT: {
17,058✔
1810
      uint16_t* plist = (uint16_t*)pCol->pData;
17,058✔
1811
      for (int32_t i = start; i < numOfRows + pInput->startRowIndex; ++i) {
17,655,110✔
1812
        if (pCol->hasNull && colDataIsNull_f(pCol, i)) {
17,638,052✔
1813
          continue;
9,060✔
1814
        }
1815

1816
        numOfElem++;
17,628,992✔
1817
        LEASTSQR_CAL(param, x, plist, i, pInfo->stepVal);
17,628,992✔
1818
      }
1819
      break;
17,058✔
1820
    }
1821

1822
    case TSDB_DATA_TYPE_UINT: {
17,058✔
1823
      uint32_t* plist = (uint32_t*)pCol->pData;
17,058✔
1824
      for (int32_t i = start; i < numOfRows + pInput->startRowIndex; ++i) {
17,655,110✔
1825
        if (pCol->hasNull && colDataIsNull_f(pCol, i)) {
17,638,052✔
1826
          continue;
9,060✔
1827
        }
1828

1829
        numOfElem++;
17,628,992✔
1830
        LEASTSQR_CAL(param, x, plist, i, pInfo->stepVal);
17,628,992✔
1831
      }
1832
      break;
17,058✔
1833
    }
1834

1835
    case TSDB_DATA_TYPE_UBIGINT: {
17,058✔
1836
      uint64_t* plist = (uint64_t*)pCol->pData;
17,058✔
1837
      for (int32_t i = start; i < numOfRows + pInput->startRowIndex; ++i) {
17,655,110✔
1838
        if (pCol->hasNull && colDataIsNull_f(pCol, i)) {
17,638,052✔
1839
          continue;
9,060✔
1840
        }
1841

1842
        numOfElem++;
17,628,992✔
1843
        LEASTSQR_CAL(param, x, plist, i, pInfo->stepVal);
17,628,992✔
1844
      }
1845
      break;
17,058✔
1846
    }
1847

1848
    case TSDB_DATA_TYPE_FLOAT: {
729,058✔
1849
      float* plist = (float*)pCol->pData;
729,058✔
1850
      for (int32_t i = start; i < numOfRows + pInput->startRowIndex; ++i) {
19,079,110✔
1851
        if (pCol->hasNull && colDataIsNull_f(pCol, i)) {
18,350,052✔
1852
          continue;
158,436✔
1853
        }
1854

1855
        numOfElem++;
18,191,616✔
1856
        LEASTSQR_CAL(param, x, plist, i, pInfo->stepVal);
18,191,616✔
1857
      }
1858
      break;
729,058✔
1859
    }
1860

1861
    case TSDB_DATA_TYPE_DOUBLE: {
366,630✔
1862
      double* plist = (double*)pCol->pData;
366,630✔
1863
      for (int32_t i = start; i < numOfRows + pInput->startRowIndex; ++i) {
18,745,646✔
1864
        if (pCol->hasNull && colDataIsNull_f(pCol, i)) {
18,379,016✔
1865
          continue;
106,236✔
1866
        }
1867

1868
        numOfElem++;
18,272,780✔
1869
        LEASTSQR_CAL(param, x, plist, i, pInfo->stepVal);
18,272,780✔
1870
      }
1871
      break;
366,630✔
1872
    }
1873
    case TSDB_DATA_TYPE_NULL: {
×
1874
      GET_RES_INFO(pCtx)->isNullRes = 1;
×
1875
      numOfElem = 1;
×
1876
      break;
×
1877
    }
1878

1879
    default:
×
1880
      break;
×
1881
  }
1882

1883
  pInfo->startVal = x;
5,210,230✔
1884
  pInfo->num += numOfElem;
5,210,230✔
1885

1886
  SET_VAL(GET_RES_INFO(pCtx), numOfElem, 1);
5,209,257✔
1887

1888
  return TSDB_CODE_SUCCESS;
5,210,230✔
1889
}
1890

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

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

1902
  if (0 == pInfo->num) {
4,393,479✔
1903
    colDataSetNULL(pCol, currentRow);
3,164,160✔
1904
    return TSDB_CODE_SUCCESS;
3,164,160✔
1905
  }
1906

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

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

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

1915
  if (0 == param00) {
1,229,319✔
1916
    colDataSetNULL(pCol, currentRow);
627,720✔
1917
    return TSDB_CODE_SUCCESS;
627,720✔
1918
  }
1919

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

1925
  param12 /= param[1][1];
601,599✔
1926

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

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

1944
  return code;
601,599✔
1945
}
1946

1947
int32_t leastSQRCombine(SqlFunctionCtx* pDestCtx, SqlFunctionCtx* pSourceCtx) {
×
1948
  SResultRowEntryInfo* pDResInfo = GET_RES_INFO(pDestCtx);
×
1949
  SLeastSQRInfo*       pDBuf = GET_ROWCELL_INTERBUF(pDResInfo);
×
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;
×
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);
×
1965
  pDResInfo->isNullRes &= pSResInfo->isNullRes;
×
1966
  return TSDB_CODE_SUCCESS;
×
1967
}
1968

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

1974
int32_t percentileFunctionSetup(SqlFunctionCtx* pCtx, SResultRowEntryInfo* pResultInfo) {
398,577✔
1975
  if (pResultInfo->initialized) {
398,577✔
1976
    return TSDB_CODE_SUCCESS;
×
1977
  }
1978
  if (TSDB_CODE_SUCCESS != functionSetup(pCtx, pResultInfo)) {
398,577✔
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);
398,577✔
1984
  SET_DOUBLE_VAL(&pInfo->minval, DBL_MAX);
398,577✔
1985
  SET_DOUBLE_VAL(&pInfo->maxval, -DBL_MAX);
398,577✔
1986
  pInfo->numOfElems = 0;
398,577✔
1987

1988
  return TSDB_CODE_SUCCESS;
398,577✔
1989
}
1990

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

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

2007
  SInputColumnInfoData* pInput = &pCtx->input;
1,809,314✔
2008
  SColumnDataAgg*       pAgg = pInput->pColumnDataAgg[0];
1,809,314✔
2009

2010
  SColumnInfoData* pCol = pInput->pData[0];
1,809,314✔
2011
  int32_t          type = pCol->info.type;
1,809,314✔
2012

2013
  SPercentileInfo* pInfo = GET_ROWCELL_INTERBUF(pResInfo);
1,809,314✔
2014
  if (pCtx->scanFlag == MAIN_SCAN && pInfo->stage == 0) {
1,809,314✔
2015
    pInfo->stage += 1;
398,577✔
2016

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

2030
  // the first stage, only acquire the min/max value
2031
  if (pInfo->stage == 0) {
1,607,714✔
2032
    if (pCtx->input.colDataSMAIsSet) {
904,657✔
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)) {
×
2041
        tmin = (double)GET_UINT64_VAL(&pAgg->min);
×
2042
        tmax = (double)GET_UINT64_VAL(&pAgg->max);
×
2043
      }
2044

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

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

2053
      pInfo->numOfElems += (pInput->numOfRows - pAgg->numOfNull);
×
2054
    } else {
2055
      // check the valid data one by one
2056
      int32_t start = pInput->startRowIndex;
904,657✔
2057
      for (int32_t i = start; i < pInput->numOfRows + start; ++i) {
17,612,158✔
2058
        if (colDataIsNull_f(pCol, i)) {
16,707,501✔
2059
          continue;
231,432✔
2060
        }
2061

2062
        char* data = colDataGetData(pCol, i);
16,476,069✔
2063

2064
        double v = 0;
16,476,069✔
2065
        GET_TYPED_DATA(v, double, type, data, typeGetTypeModFromColInfo(&pCol->info));
16,476,069✔
2066
        if (v < GET_DOUBLE_VAL(&pInfo->minval)) {
16,476,069✔
2067
          SET_DOUBLE_VAL(&pInfo->minval, v);
225,177✔
2068
        }
2069

2070
        if (v > GET_DOUBLE_VAL(&pInfo->maxval)) {
16,476,069✔
2071
          SET_DOUBLE_VAL(&pInfo->maxval, v);
13,149,557✔
2072
        }
2073

2074
        pInfo->numOfElems += 1;
16,476,069✔
2075
      }
2076
    }
2077
  } else {
2078
    // the second stage, calculate the true percentile value
2079
    int32_t start = pInput->startRowIndex;
703,057✔
2080
    for (int32_t i = start; i < pInput->numOfRows + start; ++i) {
17,152,006✔
2081
      if (colDataIsNull_f(pCol, i)) {
16,449,401✔
2082
        continue;
×
2083
      }
2084

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

2094
    SET_VAL(pResInfo, numOfElems, 1);
702,605✔
2095
  }
2096

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

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

2105
  int32_t code = 0;
397,673✔
2106
  double  v = 0;
397,673✔
2107

2108
  tMemBucket** pMemBucket = &ppInfo->pMemBucket;
397,673✔
2109
  if ((*pMemBucket) != NULL && (*pMemBucket)->total > 0) {  // check for null
397,673✔
2110
    if (pCtx->numOfParams > 2) {
196,073✔
2111
      char buf[3200] = {0};
2,712✔
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,712✔
2115

2116
      varDataVal(buf)[0] = '[';
2,712✔
2117
      for (int32_t i = 1; i < pCtx->numOfParams; ++i) {
29,832✔
2118
        SVariant* pVal = &pCtx->param[i].param;
27,120✔
2119

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

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

2127
        if (i == pCtx->numOfParams - 1) {
27,120✔
2128
          len += tsnprintf(varDataVal(buf) + len, sizeof(buf) - VARSTR_HEADER_SIZE - len, "%.6lf]", ppInfo->result);
2,712✔
2129
        } else {
2130
          len += tsnprintf(varDataVal(buf) + len, sizeof(buf) - VARSTR_HEADER_SIZE - len, "%.6lf, ", ppInfo->result);
24,408✔
2131
        }
2132
      }
2133

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

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

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

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

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

2159
      tMemBucketDestroy(pMemBucket);
193,361✔
2160
      return functionFinalize(pCtx, pBlock);
193,361✔
2161
    }
2162
  } else {
2163
    return functionFinalize(pCtx, pBlock);
201,600✔
2164
  }
2165

2166
_fin_error:
×
2167

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

2172
bool getApercentileFuncEnv(SFunctionNode* pFunc, SFuncExecEnv* pEnv) {
3,371,231✔
2173
  int32_t bytesHist =
3,371,231✔
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,371,231✔
2176
  pEnv->calcMemSize = TMAX(bytesHist, bytesDigest);
3,371,231✔
2177
  return true;
3,372,275✔
2178
}
2179

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

2187
static int8_t getApercentileAlgo(char* algoStr) {
2,906,446✔
2188
  int8_t algoType;
2189
  if (strcasecmp(algoStr, "default") == 0) {
2,906,446✔
2190
    algoType = APERCT_ALGO_DEFAULT;
1,452,402✔
2191
  } else if (strcasecmp(algoStr, "t-digest") == 0) {
1,454,044✔
2192
    algoType = APERCT_ALGO_TDIGEST;
1,455,076✔
2193
  } else {
2194
    algoType = APERCT_ALGO_UNKNOWN;
×
2195
  }
2196

2197
  return algoType;
2,906,446✔
2198
}
2199

2200
static void buildHistogramInfo(SAPercentileInfo* pInfo) {
200,766,108✔
2201
  pInfo->pHisto = (SHistogramInfo*)((char*)pInfo + sizeof(SAPercentileInfo));
200,766,108✔
2202
  pInfo->pHisto->elems = (SHistBin*)((char*)pInfo->pHisto + sizeof(SHistogramInfo));
200,769,206✔
2203
}
200,770,828✔
2204

2205
static void buildTDigestInfo(SAPercentileInfo* pInfo) {
2,922,495✔
2206
  pInfo->pTDigest = (TDigest*)((char*)pInfo + sizeof(SAPercentileInfo));
2,922,495✔
2207
}
2,924,043✔
2208

2209
int32_t apercentileFunctionSetup(SqlFunctionCtx* pCtx, SResultRowEntryInfo* pResultInfo) {
65,657,439✔
2210
  if (pResultInfo->initialized) {
65,657,439✔
2211
    return TSDB_CODE_SUCCESS;
×
2212
  }
2213
  if (TSDB_CODE_SUCCESS != functionSetup(pCtx, pResultInfo)) {
65,660,463✔
2214
    return TSDB_CODE_FUNC_SETUP_ERROR;
×
2215
  }
2216

2217
  SAPercentileInfo* pInfo = GET_ROWCELL_INTERBUF(pResultInfo);
65,661,933✔
2218

2219
  SVariant* pVal = &pCtx->param[1].param;
65,661,957✔
2220
  pInfo->percent = 0;
65,664,059✔
2221
  GET_TYPED_DATA(pInfo->percent, double, pVal->nType, &pVal->i, typeGetTypeModFromCol(pCtx->param[1].pCol));
65,661,957✔
2222

2223
  if (pCtx->numOfParams == 2) {
65,662,869✔
2224
    pInfo->algo = APERCT_ALGO_DEFAULT;
62,756,527✔
2225
  } else if (pCtx->numOfParams == 3) {
2,906,962✔
2226
    pInfo->algo = getApercentileAlgo(varDataVal(pCtx->param[2].param.pz));
2,906,434✔
2227
    if (pInfo->algo == APERCT_ALGO_UNKNOWN) {
2,906,434✔
2228
      return TSDB_CODE_FUNC_FUNTION_PARA_VALUE;
×
2229
    }
2230
  }
2231

2232
  char* tmp = (char*)pInfo + sizeof(SAPercentileInfo);
65,663,981✔
2233
  if (pInfo->algo == APERCT_ALGO_TDIGEST) {
65,659,929✔
2234
    pInfo->pTDigest = tdigestNewFrom(tmp, COMPRESSION);
1,455,592✔
2235
  } else {
2236
    buildHistogramInfo(pInfo);
64,205,831✔
2237
    pInfo->pHisto = tHistogramCreateFrom(tmp, MAX_HISTOGRAM_BIN);
64,169,975✔
2238
    qDebug("%s set up histogram, numOfElems:%" PRId64 ", numOfEntry:%d, pHisto:%p, elems:%p", __FUNCTION__,
64,210,459✔
2239
           pInfo->pHisto->numOfElems, pInfo->pHisto->numOfEntries, pInfo->pHisto, pInfo->pHisto->elems);
2240
  }
2241

2242
  return TSDB_CODE_SUCCESS;
65,665,019✔
2243
}
2244

2245
int32_t apercentileFunction(SqlFunctionCtx* pCtx) {
75,657,709✔
2246
  int32_t               numOfElems = 0;
75,657,709✔
2247
  SResultRowEntryInfo*  pResInfo = GET_RES_INFO(pCtx);
75,657,709✔
2248
  SInputColumnInfoData* pInput = &pCtx->input;
75,658,809✔
2249

2250
  SColumnInfoData* pCol = pInput->pData[0];
75,659,331✔
2251
  int32_t          type = pCol->info.type;
75,658,809✔
2252

2253
  SAPercentileInfo* pInfo = GET_ROWCELL_INTERBUF(pResInfo);
75,657,679✔
2254

2255
  int32_t start = pInput->startRowIndex;
75,657,771✔
2256
  if (pInfo->algo == APERCT_ALGO_TDIGEST) {
75,657,163✔
2257
    buildTDigestInfo(pInfo);
1,455,133✔
2258
    tdigestAutoFill(pInfo->pTDigest, COMPRESSION);
1,454,095✔
2259
    for (int32_t i = start; i < pInput->numOfRows + start; ++i) {
75,929,206✔
2260
      if (colDataIsNull_f(pCol, i)) {
74,476,149✔
2261
        continue;
38,048,811✔
2262
      }
2263
      numOfElems += 1;
36,429,420✔
2264
      char* data = colDataGetData(pCol, i);
36,429,420✔
2265

2266
      double  v = 0;  // value
36,436,206✔
2267
      int64_t w = 1;  // weigth
36,436,206✔
2268
      GET_TYPED_DATA(v, double, type, data, typeGetTypeModFromColInfo(&pCol->info));
36,436,206✔
2269
      int32_t code = tdigestAdd(pInfo->pTDigest, v, w);
36,435,684✔
2270
      if (code != TSDB_CODE_SUCCESS) {
36,426,816✔
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);
74,203,590✔
2278
    qDebug("%s before add %d elements into histogram, total:%" PRId64 ", numOfEntry:%d, pHisto:%p, elems: %p",
74,196,120✔
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,939,853,269✔
2286
      char* data = colDataGetData(pCol, i);
1,939,853,269✔
2287

2288
      double v = 0;
1,941,303,572✔
2289
      GET_TYPED_DATA(v, double, type, data, typeGetTypeModFromColInfo(&pCol->info));
1,941,303,572✔
2290
      int32_t code = tHistogramAdd(&pInfo->pHisto, v);
1,941,314,663✔
2291
      if (code != TSDB_CODE_SUCCESS) {
1,929,264,010✔
2292
        return code;
×
2293
      }
2294
    }
2295

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

2301
  SET_VAL(pResInfo, numOfElems, 1);
75,657,702✔
2302
  return TSDB_CODE_SUCCESS;
75,658,218✔
2303
}
2304

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

2312
    if (pInput->pTDigest->num_centroids == 0 && pInput->pTDigest->num_buffered_pts == 0) {
14,229✔
2313
      return TSDB_CODE_SUCCESS;
459✔
2314
    }
2315

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

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

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

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

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

2346
    if (pHisto->numOfElems <= 0) {
219,161✔
2347
      (void)memcpy(pHisto, pInput->pHisto, sizeof(SHistogramInfo) + sizeof(SHistBin) * (MAX_HISTOGRAM_BIN + 1));
204,509✔
2348
      pHisto->elems = (SHistBin*)((char*)pHisto + sizeof(SHistogramInfo));
204,509✔
2349

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

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

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

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

2377
  SInputColumnInfoData* pInput = &pCtx->input;
502,570✔
2378

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

2384
  SAPercentileInfo* pInfo = GET_ROWCELL_INTERBUF(pResInfo);
502,570✔
2385

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

2388
  bool    hasRes = false;
502,570✔
2389
  int32_t start = pInput->startRowIndex;
502,570✔
2390
  for (int32_t i = start; i < start + pInput->numOfRows; ++i) {
1,007,220✔
2391
    char* data = colDataGetData(pCol, i);
504,650✔
2392

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

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

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

2410
int32_t apercentileFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
62,603,659✔
2411
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
62,603,659✔
2412
  SAPercentileInfo*    pInfo = (SAPercentileInfo*)GET_ROWCELL_INTERBUF(pResInfo);
62,603,659✔
2413

2414
  if (pInfo->algo == APERCT_ALGO_TDIGEST) {
62,603,161✔
2415
    buildTDigestInfo(pInfo);
1,440,911✔
2416
    tdigestAutoFill(pInfo->pTDigest, COMPRESSION);
1,440,395✔
2417
    if (pInfo->pTDigest->size > 0) {
1,440,911✔
2418
      pInfo->result = tdigestQuantile(pInfo->pTDigest, pInfo->percent / 100);
1,440,911✔
2419
    } else {  // no need to free
2420
      // setNull(pCtx->pOutput, pCtx->outputType, pCtx->outputBytes);
2421
      return TSDB_CODE_SUCCESS;
×
2422
    }
2423
  } else {
2424
    buildHistogramInfo(pInfo);
61,162,748✔
2425
    if (pInfo->pHisto->numOfElems > 0) {
61,162,748✔
2426
      qDebug("%s get the final res, elements:%" PRId64 ", numOfEntry:%d, pHisto:%p, elems:%p", __FUNCTION__,
43,752,198✔
2427
             pInfo->pHisto->numOfElems, pInfo->pHisto->numOfEntries, pInfo->pHisto, pInfo->pHisto->elems);
2428

2429
      double  ratio[] = {pInfo->percent};
43,751,202✔
2430
      double* res = NULL;
43,752,696✔
2431
      int32_t code = tHistogramUniform(pInfo->pHisto, ratio, 1, &res);
43,752,696✔
2432
      if (TSDB_CODE_SUCCESS != code) {
43,752,198✔
2433
        taosMemoryFree(res);
×
2434
        return code;
×
2435
      }
2436
      pInfo->result = *res;
43,752,198✔
2437
      // memcpy(pCtx->pOutput, res, sizeof(double));
2438
      taosMemoryFree(res);
43,752,198✔
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__,
17,410,550✔
2443
             pInfo->pHisto->numOfElems, pInfo->pHisto->numOfEntries);
2444
    }
2445
  }
2446

2447
  return functionFinalize(pCtx, pBlock);
62,602,663✔
2448
}
2449

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

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

2460
  if (pInfo->algo == APERCT_ALGO_TDIGEST) {
504,650✔
2461
    (void)memcpy(varDataVal(res), pInfo, resultBytes);
14,229✔
2462
    varDataSetLen(res, resultBytes);
14,229✔
2463
  } else {
2464
    (void)memcpy(varDataVal(res), pInfo, resultBytes);
490,421✔
2465
    varDataSetLen(res, resultBytes);
490,421✔
2466
  }
2467

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

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

2477
  taosMemoryFree(res);
504,650✔
2478
  return code;
504,650✔
2479
}
2480

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

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);
×
2491
  if (TSDB_CODE_SUCCESS != code) {
×
2492
    return code;
×
2493
  }
2494
  pDResInfo->numOfRes = TMAX(pDResInfo->numOfRes, pSResInfo->numOfRes);
×
2495
  pDResInfo->isNullRes &= pSResInfo->isNullRes;
×
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) {
839,426✔
2501
  char numVal[8] = {0};
839,426✔
2502
  switch (pkType) {
839,426✔
2503
    case TSDB_DATA_TYPE_INT:
173,219✔
2504
      *(int32_t*)numVal = (int32_t)VALUE_GET_TRIVIAL_DATUM(pVal);
173,219✔
2505
      break;
173,219✔
2506
    case TSDB_DATA_TYPE_UINT:
139,260✔
2507
      *(uint32_t*)numVal = (uint32_t)VALUE_GET_TRIVIAL_DATUM(pVal);
139,260✔
2508
      break;
139,260✔
2509
    case TSDB_DATA_TYPE_BIGINT:
165,540✔
2510
      *(int64_t*)numVal = (int64_t)VALUE_GET_TRIVIAL_DATUM(pVal);
165,540✔
2511
      break;
165,540✔
2512
    case TSDB_DATA_TYPE_UBIGINT:
139,917✔
2513
      *(uint64_t*)numVal = (uint64_t)VALUE_GET_TRIVIAL_DATUM(pVal);
139,917✔
2514
      break;
139,917✔
2515
    default:
221,490✔
2516
      break;
221,490✔
2517
  }
2518
  char*         blockData = (IS_NUMERIC_TYPE(pkType)) ? (char*)numVal : (char*)pVal->pData;
839,426✔
2519
  __compar_fn_t fn = getKeyComparFunc(pkType, order);
839,426✔
2520
  return fn(pkData, blockData);
839,426✔
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✔
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;
480,174✔
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,427,331✔
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) {
385,773✔
2545
        return FUNC_DATA_REQUIRED_NOT_LOAD;
82,932✔
2546
      }
2547
    }
2548
    return FUNC_DATA_REQUIRED_DATA_LOAD;
760,131✔
2549
  } else {
2550
    return FUNC_DATA_REQUIRED_DATA_LOAD;
8,068,481✔
2551
  }
2552
}
2553

2554
EFuncDataRequired lastDynDataReq(void* pRes, SDataBlockInfo* pBlockInfo) {
53,380,591✔
2555
  SResultRowEntryInfo* pEntry = (SResultRowEntryInfo*)pRes;
53,380,591✔
2556

2557
  // not initialized yet, data is required
2558
  if (pEntry == NULL) {
53,380,591✔
2559
    return FUNC_DATA_REQUIRED_DATA_LOAD;
×
2560
  }
2561

2562
  SFirstLastRes* pResult = GET_ROWCELL_INTERBUF(pEntry);
53,380,591✔
2563
  if (pResult->hasResult) {
53,396,205✔
2564
    if (pResult->pkBytes > 0) {
45,469,004✔
2565
      pResult->pkData = pResult->buf + pResult->bytes;
687,356✔
2566
    } else {
2567
      pResult->pkData = NULL;
44,782,027✔
2568
    }
2569
    if (pResult->ts > pBlockInfo->window.ekey) {
45,468,827✔
2570
      return FUNC_DATA_REQUIRED_NOT_LOAD;
26,293,772✔
2571
    } else if (pResult->ts == pBlockInfo->window.ekey && pResult->pkData) {
19,175,611✔
2572
      if (comparePkDataWithSValue(pResult->pkType, pResult->pkData, pBlockInfo->pks + 1, TSDB_ORDER_DESC) < 0) {
452,996✔
2573
        return FUNC_DATA_REQUIRED_NOT_LOAD;
115,068✔
2574
      }
2575
    }
2576
    return FUNC_DATA_REQUIRED_DATA_LOAD;
19,055,813✔
2577
  } else {
2578
    return FUNC_DATA_REQUIRED_DATA_LOAD;
7,932,799✔
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,773,871,359✔
2584

2585
bool getFirstLastFuncEnv(SFunctionNode* pFunc, SFuncExecEnv* pEnv) {
76,890,695✔
2586
  SColumnNode* pNode = (SColumnNode*)nodesListGetNode(pFunc->pParameterList, 0);
76,890,695✔
2587
  // TODO: change SFunctionNode to add pk info
2588
  int32_t pkBytes = (pFunc->hasPk) ? pFunc->pkBytes : 0;
76,910,072✔
2589
  pEnv->calcMemSize = getFirstLastInfoSize(pNode->node.resType.bytes, pkBytes);
76,907,126✔
2590
  return true;
76,899,628✔
2591
}
2592

2593
bool getSelectivityFuncEnv(SFunctionNode* pFunc, SFuncExecEnv* pEnv) {
14,182,456✔
2594
  SColumnNode* pNode = (SColumnNode*)nodesListGetNode(pFunc->pParameterList, 0);
14,182,456✔
2595
  pEnv->calcMemSize = pNode->node.resType.bytes;
14,183,059✔
2596
  return true;
14,181,375✔
2597
}
2598

2599

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

2605
bool getGroupKeyFuncEnv(SFunctionNode* pFunc, SFuncExecEnv* pEnv) {
63,184,893✔
2606
  SColumnNode* pNode = (SColumnNode*)nodesListGetNode(pFunc->pParameterList, 0);
63,184,893✔
2607
  pEnv->calcMemSize = sizeof(SGroupKeyInfo) + pNode->node.resType.bytes;
63,195,902✔
2608
  return true;
63,186,447✔
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✔
2621
    return TSDB_CODE_SUCCESS;
×
2622
  }
2623
  if (TSDB_CODE_SUCCESS != functionSetup(pCtx, pResInfo)) {
2,147,483,647✔
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) {
109,727,177✔
2634
  if (pCtx->subsidiaries.rowLen == 0) {
109,727,177✔
2635
    int32_t rowLen = 0;
4,596,814✔
2636
    for (int32_t j = 0; j < pCtx->subsidiaries.num; ++j) {
10,745,541✔
2637
      SqlFunctionCtx* pc = pCtx->subsidiaries.pCtx[j];
6,153,433✔
2638
      rowLen += pc->pExpr->base.resSchema.bytes;
6,151,707✔
2639
    }
2640

2641
    pCtx->subsidiaries.rowLen = rowLen + pCtx->subsidiaries.num * sizeof(bool);
4,592,921✔
2642
    pCtx->subsidiaries.buf = taosMemoryMalloc(pCtx->subsidiaries.rowLen);
4,596,276✔
2643
    if (NULL == pCtx->subsidiaries.buf) {
4,599,391✔
2644
      return terrno;
×
2645
    }
2646
  }
2647
  return TSDB_CODE_SUCCESS;
109,726,137✔
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) {
69,577,615✔
2659
    code = saveTupleData(pCtx, rowIndex, pSrcBlock, &pInfo->pos);
56,949,714✔
2660
  } else if (!noElements) {
12,629,117✔
2661
    code = updateTupleData(pCtx, rowIndex, pSrcBlock, &pInfo->pos);
12,612,698✔
2662
  } else {
2663
  }  // dothing
2664

2665
  return code;
69,580,341✔
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)) {
173,358,181✔
2685
      pInfo->pkBytes = calcStrBytesByType(pInfo->pkType, pkData);
57,694,652✔
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);
173,349,469✔
2693
    pInfo->pkData = pInfo->buf + pInfo->bytes;
173,358,644✔
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✔
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;
165,197,796✔
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;
10,067,027✔
2728
    pInfo->pkBytes = pkCol->info.bytes;
10,071,380✔
2729
    pkCompareFn = getKeyComparFunc(pInfo->pkType, TSDB_ORDER_ASC);
10,069,489✔
2730
  }
2731

2732
  // All null data column, return directly.
2733
  if (pInput->colDataSMAIsSet && (pInput->pColumnDataAgg[0]->numOfNull == pInput->totalRows) &&
2,147,483,647✔
2734
      pInputCol->hasNull == true) {
×
2735
    // save selectivity value for column consisted of all null values
2736
    int32_t code = firstlastSaveTupleData(pCtx->pSrcBlock, pInput->startRowIndex, pCtx, pInfo, true);
×
2737
    if (code != TSDB_CODE_SUCCESS) {
×
2738
      return code;
×
2739
    }
2740
    pInfo->nullTupleSaved = true;
×
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);
179,375,200✔
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✔
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✔
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;
165,174,806✔
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;
10,292,579✔
2863
    pInfo->pkBytes = pkCol->info.bytes;
10,290,728✔
2864
    pkCompareFn = getKeyComparFunc(pInfo->pkType, TSDB_ORDER_DESC);
10,294,430✔
2865
  }
2866

2867
  // All null data column, return directly.
2868
  if (pInput->colDataSMAIsSet && (pInput->pColumnDataAgg[0]->numOfNull == pInput->totalRows) &&
2,147,483,647✔
2869
      pInputCol->hasNull == true) {
×
2870
    // save selectivity value for column consisted of all null values
2871
    int32_t code = firstlastSaveTupleData(pCtx->pSrcBlock, pInput->startRowIndex, pCtx, pInfo, true);
×
2872
    if (code != TSDB_CODE_SUCCESS) {
×
2873
      return code;
×
2874
    }
2875
    pInfo->nullTupleSaved = true;
×
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];
133,845,201✔
2951
        chosen = i + 1;
133,845,201✔
2952
      }
2953

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

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

2964
      if (pResInfo->numOfRes == 0 || pInfo->ts < cts) {
2,147,483,647✔
2965
        char*   data = colDataGetData(pInputCol, chosen);
163,705,105✔
2966
        int32_t code = doSaveCurrentVal(pCtx, chosen, cts, NULL, type, data);
163,668,454✔
2967
        if (code != TSDB_CODE_SUCCESS) {
163,665,594✔
2968
          return code;
×
2969
        }
2970
        pResInfo->numOfRes = 1;
163,665,594✔
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);
883,519,543✔
2977
        int32_t code = doSaveCurrentVal(pCtx, i, pts[i], NULL, type, data);
879,945,757✔
2978
        if (code != TSDB_CODE_SUCCESS) {
879,663,454✔
2979
          return code;
×
2980
        }
2981
        pResInfo->numOfRes = 1;
879,663,454✔
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);
179,135,233✔
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✔
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✔
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,352,047,991✔
3028
  if (!pInput->hasResult) {
1,352,047,991✔
3029
    return false;
×
3030
  }
3031
  __compar_fn_t pkCompareFn = NULL;
1,352,047,991✔
3032
  if (pInput->pkData) {
1,352,047,991✔
3033
    pkCompareFn = getKeyComparFunc(pInput->pkType, (isFirst) ? TSDB_ORDER_ASC : TSDB_ORDER_DESC);
2,065,476✔
3034
  }
3035
  if (pOutput->hasResult) {
1,352,047,991✔
3036
    if (isFirst) {
738,929,140✔
3037
      if (pInput->ts > pOutput->ts ||
639,151,615✔
3038
          (pInput->ts == pOutput->ts && pkCompareFn && pkCompareFn(pInput->pkData, pOutput->pkData) > 0)) {
636,490,733✔
3039
        return false;
2,660,882✔
3040
      }
3041
    } else {
3042
      if (pInput->ts < pOutput->ts ||
99,777,525✔
3043
          (pInput->ts == pOutput->ts && pkCompareFn && pkCompareFn(pInput->pkData, pOutput->pkData) > 0)) {
96,067,492✔
3044
        return false;
3,710,033✔
3045
      }
3046
    }
3047
  }
3048

3049
  pOutput->isNull = pInput->isNull;
1,345,677,299✔
3050
  pOutput->ts = pInput->ts;
1,345,677,299✔
3051
  pOutput->bytes = pInput->bytes;
1,345,677,522✔
3052
  pOutput->pkType = pInput->pkType;
1,345,678,191✔
3053

3054
  (void)memcpy(pOutput->buf, pInput->buf, pOutput->bytes);
1,345,678,414✔
3055
  if (pInput->pkData) {
1,345,677,745✔
3056
    pOutput->pkBytes = pInput->pkBytes;
1,965,873✔
3057
    (void)memcpy(pOutput->buf + pOutput->bytes, pInput->pkData, pOutput->pkBytes);
1,965,873✔
3058
    pOutput->pkData = pOutput->buf + pOutput->bytes;
1,965,873✔
3059
  }
3060
  return true;
1,345,678,414✔
3061
}
3062

3063
static int32_t firstLastTransferInfo(SqlFunctionCtx* pCtx, SFirstLastRes* pInput, SFirstLastRes* pOutput, bool isFirst,
1,352,047,991✔
3064
                                     int32_t rowIndex) {
3065
  if (firstLastTransferInfoImpl(pInput, pOutput, isFirst)) {
1,352,047,991✔
3066
    int32_t code = firstlastSaveTupleData(pCtx->pSrcBlock, rowIndex, pCtx, pOutput, false);
1,345,678,414✔
3067
    if (TSDB_CODE_SUCCESS != code) {
1,345,677,745✔
3068
      return code;
×
3069
    }
3070
    pOutput->hasResult = true;
1,345,677,745✔
3071
  }
3072
  return TSDB_CODE_SUCCESS;
1,352,048,660✔
3073
}
3074

3075
static int32_t firstLastFunctionMergeImpl(SqlFunctionCtx* pCtx, bool isFirstQuery) {
646,462,922✔
3076
  SInputColumnInfoData* pInput = &pCtx->input;
646,462,922✔
3077
  SColumnInfoData*      pCol = pInput->pData[0];
646,462,922✔
3078

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

3084
  if (pCol->info.type != TSDB_DATA_TYPE_BINARY) {
646,463,368✔
3085
    return TSDB_CODE_FUNC_FUNTION_PARA_TYPE;
×
3086
  }
3087

3088
  SFirstLastRes* pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
646,463,368✔
3089

3090
  int32_t start = pInput->startRowIndex;
646,463,368✔
3091
  int32_t numOfElems = 0;
646,464,037✔
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;
235,053,895✔
3096
    }
3097
    char*          data = colDataGetData(pCol, i);
1,352,047,322✔
3098
    SFirstLastRes* pInputInfo = (SFirstLastRes*)varDataVal(data);
1,352,048,214✔
3099
    if (pCtx->hasPrimaryKey) {
1,352,048,214✔
3100
      pInputInfo->pkData = pInputInfo->buf + pInputInfo->bytes;
2,065,476✔
3101
    } else {
3102
      pInputInfo->pkData = NULL;
1,349,982,515✔
3103
    }
3104

3105
    int32_t code = firstLastTransferInfo(pCtx, pInputInfo, pInfo, isFirstQuery, i);
1,352,047,768✔
3106
    if (code != TSDB_CODE_SUCCESS) {
1,352,048,660✔
3107
      return code;
×
3108
    }
3109
    if (!numOfElems) {
1,352,048,660✔
3110
      numOfElems = pInputInfo->hasResult ? 1 : 0;
635,068,953✔
3111
    }
3112
  }
3113

3114
  if (numOfElems == 0) {
646,460,915✔
3115
    int32_t code = firstlastSaveTupleData(pCtx->pSrcBlock, pInput->startRowIndex, pCtx, pInfo, true);
11,395,307✔
3116
    if (code != TSDB_CODE_SUCCESS) {
11,395,307✔
3117
      return code;
×
3118
    }
3119
    pInfo->nullTupleSaved = true;
11,395,307✔
3120
  }
3121

3122
  SET_VAL(GET_RES_INFO(pCtx), numOfElems, 1);
646,461,584✔
3123
  return TSDB_CODE_SUCCESS;
646,461,584✔
3124
}
3125

3126
int32_t firstFunctionMerge(SqlFunctionCtx* pCtx) { return firstLastFunctionMergeImpl(pCtx, true); }
370,778,294✔
3127

3128
int32_t lastFunctionMerge(SqlFunctionCtx* pCtx) { return firstLastFunctionMergeImpl(pCtx, false); }
275,685,074✔
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✔
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,939,732,219✔
3145
    return setNullSelectivityValue(pCtx, pBlock, pBlock->info.rows);
1,939,732,219✔
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✔
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✔
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,683,724,381✔
3162
  int32_t code = TSDB_CODE_SUCCESS;
1,683,724,381✔
3163

3164
  SResultRowEntryInfo* pEntryInfo = GET_RES_INFO(pCtx);
1,683,724,381✔
3165
  SFirstLastRes*       pRes = GET_ROWCELL_INTERBUF(pEntryInfo);
1,684,311,446✔
3166

3167
  int32_t resultBytes = getFirstLastInfoSize(pRes->bytes, pRes->pkBytes);
1,684,359,858✔
3168

3169
  // todo check for failure
3170
  char* res = taosMemoryCalloc(resultBytes + VARSTR_HEADER_SIZE, sizeof(char));
1,683,806,546✔
3171
  if (NULL == res) {
1,677,469,348✔
3172
    return terrno;
×
3173
  }
3174
  (void)memcpy(varDataVal(res), pRes, resultBytes);
1,677,469,348✔
3175

3176
  varDataSetLen(res, resultBytes);
1,677,814,895✔
3177

3178
  int32_t          slotId = pCtx->pExpr->base.resSchema.slotId;
1,683,760,149✔
3179
  SColumnInfoData* pCol = taosArrayGet(pBlock->pDataBlock, slotId);
1,683,428,146✔
3180
  if (NULL == pCol) {
1,683,087,119✔
3181
    taosMemoryFree(res);
×
3182
    return TSDB_CODE_OUT_OF_RANGE;
×
3183
  }
3184

3185
  if (pEntryInfo->numOfRes == 0) {
1,683,087,119✔
3186
    colDataSetNULL(pCol, pBlock->info.rows);
244,426,282✔
3187
    code = setNullSelectivityValue(pCtx, pBlock, pBlock->info.rows);
244,458,683✔
3188
  } else {
3189
    code = colDataSetVal(pCol, pBlock->info.rows, res, false);
1,439,240,832✔
3190
    if (TSDB_CODE_SUCCESS != code) {
1,439,503,517✔
3191
      taosMemoryFree(res);
×
3192
      return code;
×
3193
    }
3194
    code = setSelectivityValue(pCtx, pBlock, &pRes->pos, pBlock->info.rows);
1,439,503,517✔
3195
  }
3196
  taosMemoryFree(res);
1,683,554,834✔
3197
  return code;
1,683,750,621✔
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

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

3208
  pDBuf->hasResult = firstLastTransferInfoImpl(pSBuf, pDBuf, false);
×
3209
  pDResInfo->numOfRes = TMAX(pDResInfo->numOfRes, pSResInfo->numOfRes);
×
3210
  pDResInfo->isNullRes &= pSResInfo->isNullRes;
×
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,298,667✔
3215
  SInputColumnInfoData* pInput = &pCtx->input;
32,298,667✔
3216
  SColumnInfoData*      pInputCol = pInput->pData[0];
32,304,034✔
3217
  SColumnInfoData*      pkCol = pInput->pPrimaryKey;
32,303,102✔
3218

3219
  if (colDataIsNull_s(pInputCol, rowIndex)) {
64,599,559✔
3220
    pInfo->isNull = true;
8,143,864✔
3221
  } else {
3222
    pInfo->isNull = false;
24,153,341✔
3223

3224
    if (IS_VAR_DATA_TYPE(pInputCol->info.type)) {
24,157,459✔
3225
      pInfo->bytes = calcStrBytesByType(pInputCol->info.type, pData);
4,887,705✔
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,160,999✔
3234
  }
3235

3236
  if (pCtx->hasPrimaryKey && !colDataIsNull_s(pkCol, rowIndex)) {
40,857,113✔
3237
    char* pkData = colDataGetData(pkCol, rowIndex);
8,566,557✔
3238
    if (IS_VAR_DATA_TYPE(pInfo->pkType)) {
8,563,404✔
3239
      pInfo->pkBytes = calcStrBytesByType(pInfo->pkType, pkData);
2,845,306✔
3240
    }
3241
    (void)memcpy(pInfo->buf + pInfo->bytes, pkData, pInfo->pkBytes);
8,563,336✔
3242
    pInfo->pkData = pInfo->buf + pInfo->bytes;
8,562,096✔
3243
  }
3244
  pInfo->ts = cts;
32,287,915✔
3245
  int32_t code = firstlastSaveTupleData(pCtx->pSrcBlock, rowIndex, pCtx, pInfo, false);
32,299,847✔
3246
  if (code != TSDB_CODE_SUCCESS) {
32,294,109✔
3247
    return code;
×
3248
  }
3249

3250
  pInfo->hasResult = true;
32,294,109✔
3251

3252
  return TSDB_CODE_SUCCESS;
32,296,489✔
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,719✔
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;
9,618,560✔
3276
    pInfo->pkBytes = pkCol->info.bytes;
9,617,869✔
3277
    pkCompareFn = getKeyComparFunc(pInfo->pkType, TSDB_ORDER_DESC);
9,622,262✔
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) {
20,454,206✔
3284
      bool  isNull = colDataIsNull(pInputCol, pInput->numOfRows, i, NULL);
10,226,223✔
3285
      char* data = isNull ? NULL : colDataGetData(pInputCol, i);
10,226,663✔
3286
      TSKEY cts = getRowPTs(pInput->pPTS, i);
10,227,103✔
3287
      numOfElems++;
10,229,303✔
3288

3289
      if (pResInfo->numOfRes == 0 || pInfo->ts < cts) {
10,229,303✔
3290
        int32_t code = doSaveLastrow(pCtx, data, i, cts, pInfo);
2,868,903✔
3291
        if (code != TSDB_CODE_SUCCESS) return code;
2,867,143✔
3292
      }
3293

3294
      break;
10,227,543✔
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,407,235✔
3307
        if (code != TSDB_CODE_SUCCESS) return code;
18,798,501✔
3308
      }
3309
      break;
2,147,483,647✔
3310
    }
3311
  } else {
3312
    int64_t* pts = (int64_t*)pInput->pPTS->pData;
12,161,910✔
3313
    int      from = -1;
10,168,257✔
3314
    int32_t  i = -1;
10,168,874✔
3315
    while (funcInputGetNextRowIndex(pInput, from, false, &i, &from)) {
184,343,240✔
3316
      bool  isNull = colDataIsNull(pInputCol, pInput->numOfRows, i, NULL);
174,167,862✔
3317
      char* data = isNull ? NULL : colDataGetData(pInputCol, i);
174,174,963✔
3318
      TSKEY cts = pts[i];
174,164,488✔
3319

3320
      numOfElems++;
174,174,508✔
3321
      char* pkData = NULL;
174,174,508✔
3322
      if (pCtx->hasPrimaryKey) {
174,174,508✔
3323
        pkData = colDataGetData(pkCol, i);
169,543,317✔
3324
      }
3325
      if (pResInfo->numOfRes == 0 || pInfo->ts < cts ||
174,198,383✔
3326
          (pInfo->ts == pts[i] && pkCompareFn && pkCompareFn(pkData, pInfo->pkData) < 0)) {
164,052,324✔
3327
        int32_t code = doSaveLastrow(pCtx, data, i, cts, pInfo);
10,125,008✔
3328
        if (code != TSDB_CODE_SUCCESS) {
10,130,253✔
3329
          return code;
×
3330
        }
3331
        pResInfo->numOfRes = 1;
10,130,253✔
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) {
521,787✔
3341
  pEnv->calcMemSize = sizeof(SDiffInfo);
521,787✔
3342
  return true;
521,787✔
3343
}
3344

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

3365
static int32_t doSetPrevVal(SDiffInfo* pDiffInfo, int32_t type, const char* pv, int64_t ts) {
5,521,897✔
3366
  switch (type) {
5,521,897✔
3367
    case TSDB_DATA_TYPE_BOOL:
3,857✔
3368
      pDiffInfo->prev.i64 = *(bool*)pv ? 1 : 0;
3,857✔
3369
      break;
3,857✔
3370
    case TSDB_DATA_TYPE_UTINYINT:
39,200✔
3371
    case TSDB_DATA_TYPE_TINYINT:
3372
      pDiffInfo->prev.i64 = *(int8_t*)pv;
39,200✔
3373
      break;
39,200✔
3374
    case TSDB_DATA_TYPE_UINT:
5,248,532✔
3375
    case TSDB_DATA_TYPE_INT:
3376
      pDiffInfo->prev.i64 = *(int32_t*)pv;
5,248,532✔
3377
      break;
5,248,532✔
3378
    case TSDB_DATA_TYPE_USMALLINT:
35,642✔
3379
    case TSDB_DATA_TYPE_SMALLINT:
3380
      pDiffInfo->prev.i64 = *(int16_t*)pv;
35,642✔
3381
      break;
35,642✔
3382
    case TSDB_DATA_TYPE_TIMESTAMP:
112,331✔
3383
    case TSDB_DATA_TYPE_UBIGINT:
3384
    case TSDB_DATA_TYPE_BIGINT:
3385
      pDiffInfo->prev.i64 = *(int64_t*)pv;
112,331✔
3386
      break;
112,331✔
3387
    case TSDB_DATA_TYPE_FLOAT:
21,857✔
3388
      pDiffInfo->prev.d64 = *(float*)pv;
21,857✔
3389
      break;
21,857✔
3390
    case TSDB_DATA_TYPE_DOUBLE:
60,478✔
3391
      pDiffInfo->prev.d64 = *(double*)pv;
60,478✔
3392
      break;
60,478✔
3393
    default:
×
3394
      return TSDB_CODE_FUNC_FUNTION_PARA_TYPE;
×
3395
  }
3396
  pDiffInfo->prevTs = ts;
5,521,897✔
3397
  pDiffInfo->hasPrev = true;
5,521,897✔
3398
  return TSDB_CODE_SUCCESS;
5,521,897✔
3399
}
3400

3401
static bool diffIsNegtive(SDiffInfo* pDiffInfo, int32_t type, const char* pv) {
3,302,886✔
3402
  switch (type) {
3,302,886✔
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: {
661,848✔
3408
      int64_t v = *(int32_t*)pv;
661,848✔
3409
      return v < pDiffInfo->prev.i64;
661,848✔
3410
    }
3411
    case TSDB_DATA_TYPE_BOOL: {
×
3412
      int64_t v = *(bool*)pv;
×
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: {
690,720✔
3420
      int64_t v = *(int8_t*)pv;
690,720✔
3421
      return v < pDiffInfo->prev.i64;
690,720✔
3422
    }
3423
    case TSDB_DATA_TYPE_USMALLINT: {
×
3424
      int64_t v = *(uint16_t*)pv;
×
3425
      return v < pDiffInfo->prev.i64;
×
3426
    }
3427
    case TSDB_DATA_TYPE_SMALLINT: {
168,462✔
3428
      int64_t v = *(int16_t*)pv;
168,462✔
3429
      return v < pDiffInfo->prev.i64;
168,462✔
3430
    }
3431
    case TSDB_DATA_TYPE_UBIGINT: {
3,432✔
3432
      uint64_t v = *(uint64_t*)pv;
3,432✔
3433
      return v < (uint64_t)pDiffInfo->prev.i64;
3,432✔
3434
    }
3435
    case TSDB_DATA_TYPE_TIMESTAMP:
459,714✔
3436
    case TSDB_DATA_TYPE_BIGINT: {
3437
      int64_t v = *(int64_t*)pv;
459,714✔
3438
      return v < pDiffInfo->prev.i64;
459,714✔
3439
    }
3440
    case TSDB_DATA_TYPE_FLOAT: {
657,918✔
3441
      float v = *(float*)pv;
657,918✔
3442
      return v < pDiffInfo->prev.d64;
657,918✔
3443
    }
3444
    case TSDB_DATA_TYPE_DOUBLE: {
660,792✔
3445
      double v = *(double*)pv;
660,792✔
3446
      return v < pDiffInfo->prev.d64;
660,792✔
3447
    }
3448
    default:
×
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;
439,265✔
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);
971,142✔
3463
    pOutput->hasNull = true;
971,142✔
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) {
28,217,235✔
3471
  double delta = v - pDiffInfo->prev.d64;
28,217,235✔
3472
  if (delta < 0 && ignoreNegative(pDiffInfo->ignoreOption)) {
28,217,235✔
3473
    colDataSetNull_f_s(pOutput, pos);
662,127✔
3474
  } else {
3475
    colDataSetDouble(pOutput, pos, &delta);
27,555,108✔
3476
  }
3477
  pDiffInfo->prev.d64 = v;
28,217,235✔
3478
}
28,217,235✔
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);
63,564✔
3484
    return doSetPrevVal(pDiffInfo, type, pv, ts);
63,564✔
3485
  }
3486
  pDiffInfo->prevTs = ts;
2,147,483,647✔
3487
  switch (type) {
2,147,483,647✔
3488
    case TSDB_DATA_TYPE_UINT: {
433,259✔
3489
      int64_t v = *(uint32_t*)pv;
433,259✔
3490
      tryToSetInt64(pDiffInfo, type, pOutput, v, pos);
433,259✔
3491
      break;
433,259✔
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,369,718✔
3499
      int64_t v = *(bool*)pv;
4,369,718✔
3500
      tryToSetInt64(pDiffInfo, type, pOutput, v, pos);
4,369,718✔
3501
      break;
4,369,718✔
3502
    }
3503
    case TSDB_DATA_TYPE_UTINYINT: {
57,915✔
3504
      int64_t v = *(uint8_t*)pv;
57,915✔
3505
      tryToSetInt64(pDiffInfo, type, pOutput, v, pos);
57,915✔
3506
      break;
57,915✔
3507
    }
3508
    case TSDB_DATA_TYPE_TINYINT: {
10,186,646✔
3509
      int64_t v = *(int8_t*)pv;
10,186,646✔
3510
      tryToSetInt64(pDiffInfo, type, pOutput, v, pos);
10,186,646✔
3511
      break;
10,186,646✔
3512
    }
3513
    case TSDB_DATA_TYPE_USMALLINT: {
57,915✔
3514
      int64_t v = *(uint16_t*)pv;
57,915✔
3515
      tryToSetInt64(pDiffInfo, type, pOutput, v, pos);
57,915✔
3516
      break;
57,915✔
3517
    }
3518
    case TSDB_DATA_TYPE_SMALLINT: {
10,515,458✔
3519
      int64_t v = *(int16_t*)pv;
10,515,458✔
3520
      tryToSetInt64(pDiffInfo, type, pOutput, v, pos);
10,515,458✔
3521
      break;
10,515,458✔
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,762,079✔
3531
      double v = *(float*)pv;
13,762,079✔
3532
      tryToSetDouble(pDiffInfo, pOutput, v, pos);
13,762,079✔
3533
      break;
13,762,079✔
3534
    }
3535
    case TSDB_DATA_TYPE_DOUBLE: {
14,455,156✔
3536
      double v = *(double*)pv;
14,455,156✔
3537
      tryToSetDouble(pDiffInfo, pOutput, v, pos);
14,455,156✔
3538
      break;
14,455,156✔
3539
    }
3540
    default:
×
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 (pInput->numOfRows == 0) {
2,147,483,647✔
3553
      return false;
28,287,462✔
3554
    }
3555
    if (from == -1) {
2,147,483,647✔
3556
      from = pInput->startRowIndex;
2,147,483,647✔
3557
    } else if (from >= pInput->numOfRows + pInput->startRowIndex) {
2,147,483,647✔
3558
      return false;
2,147,483,647✔
3559
    }
3560
    *pRowIndex = from;
2,147,483,647✔
3561
    *nextFrom = from + 1;
2,147,483,647✔
3562
    return true;
2,147,483,647✔
3563
  } else {
3564
    if (from == -1) {
558,532,431✔
3565
      from = pInput->startRowIndex;
29,973,144✔
3566
    } else if (from >= pInput->numOfRows + pInput->startRowIndex) {
528,559,287✔
3567
      return false;
29,995,516✔
3568
    }
3569
    TSKEY*           tsList = (int64_t*)pInput->pPTS->pData;
528,620,352✔
3570
    SColumnInfoData* pkCol = pInput->pPrimaryKey;
528,636,977✔
3571
    int8_t           pkType = pkCol->info.type;
528,652,442✔
3572
    int32_t          order = (firstOccur) ? TSDB_ORDER_ASC : TSDB_ORDER_DESC;
528,722,185✔
3573
    __compar_fn_t    compareFunc = getKeyComparFunc(pkType, order);
528,722,185✔
3574
    int32_t          select = from;
528,577,801✔
3575
    char*            val = colDataGetData(pkCol, select);
528,577,801✔
3576
    while (from < pInput->numOfRows + pInput->startRowIndex - 1 && tsList[from + 1] == tsList[from]) {
1,315,882,271✔
3577
      char* val1 = colDataGetData(pkCol, from + 1);
787,114,234✔
3578
      if (compareFunc(val1, val) < 0) {
787,287,755✔
3579
        select = from + 1;
244,078,659✔
3580
        val = val1;
244,078,659✔
3581
      }
3582
      from = from + 1;
787,193,651✔
3583
    }
3584
    *pRowIndex = select;
527,734,021✔
3585
    *nextFrom = from + 1;
528,692,945✔
3586
    return true;
528,714,432✔
3587
  }
3588
}
3589

3590
bool getForecastConfEnv(SFunctionNode* UNUSED_PARAM(pFunc), SFuncExecEnv* pEnv) {
×
3591
  pEnv->calcMemSize = sizeof(double);
×
3592
  return true;
×
3593
}
3594

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

3599
  if (pRow->isDataNull || !pDiffInfo->hasPrev) {
2,147,483,647✔
3600
    return true;
12,389,058✔
3601
  } else if (ignoreNegative(pDiffInfo->ignoreOption)) {
2,147,483,647✔
3602
    return diffIsNegtive(pDiffInfo, pCtx->input.pData[0]->info.type, pRow->pData);
3,302,886✔
3603
  }
3604
  return false;
2,147,483,647✔
3605
}
3606

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

3613
int32_t trySetPreVal(SqlFunctionCtx* pCtx, SFuncInputRow* pRow) {
5,628,852✔
3614
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
5,628,852✔
3615
  SDiffInfo*           pDiffInfo = GET_ROWCELL_INTERBUF(pResInfo);
5,628,852✔
3616
  pDiffInfo->isFirstRow = false;
5,628,852✔
3617
  if (pRow->isDataNull) {
5,628,852✔
3618
    return TSDB_CODE_SUCCESS;
170,519✔
3619
  }
3620

3621
  SInputColumnInfoData* pInput = &pCtx->input;
5,458,333✔
3622
  SColumnInfoData*      pInputCol = pInput->pData[0];
5,458,333✔
3623
  int8_t                inputType = pInputCol->info.type;
5,458,333✔
3624

3625
  char* pv = pRow->pData;
5,458,333✔
3626
  return doSetPrevVal(pDiffInfo, inputType, pv, pRow->ts);
5,458,333✔
3627
}
3628

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

3633
  SInputColumnInfoData* pInput = &pCtx->input;
2,147,483,647✔
3634
  SColumnInfoData*      pInputCol = pInput->pData[0];
2,147,483,647✔
3635
  int8_t                inputType = pInputCol->info.type;
2,147,483,647✔
3636
  SColumnInfoData*      pOutput = (SColumnInfoData*)pCtx->pOutput;
2,147,483,647✔
3637
  int32_t               code = TSDB_CODE_SUCCESS;
2,147,483,647✔
3638
  if (pRow->isDataNull) {
2,147,483,647✔
3639
    colDataSetNull_f_s(pOutput, pos);
6,703,935✔
3640
    pOutput->hasNull = true;
6,703,935✔
3641

3642
    // handle selectivity
3643
    if (pCtx->subsidiaries.num > 0) {
6,703,935✔
3644
      code = appendSelectivityCols(pCtx, pRow->block, pRow->rowIndex, pos);
20,584✔
3645
      if (code != TSDB_CODE_SUCCESS) {
20,584✔
3646
        return code;
×
3647
      }
3648
    }
3649
    return TSDB_CODE_SUCCESS;
6,703,935✔
3650
  }
3651

3652
  char* pv = pRow->pData;
2,147,483,647✔
3653

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

3669
  return TSDB_CODE_SUCCESS;
2,147,483,647✔
3670
}
3671

3672
int32_t diffFunction(SqlFunctionCtx* pCtx) { return TSDB_CODE_SUCCESS; }
44,481,979✔
3673

3674
int32_t diffFunctionByRow(SArray* pCtxArray) {
44,458,813✔
3675
  int32_t code = TSDB_CODE_SUCCESS;
44,458,813✔
3676
  int     diffColNum = pCtxArray->size;
44,458,813✔
3677
  if (diffColNum == 0) {
44,458,813✔
3678
    return TSDB_CODE_SUCCESS;
×
3679
  }
3680
  int32_t numOfElems = 0;
44,458,813✔
3681

3682
  SArray* pRows = taosArrayInit_s(sizeof(SFuncInputRow), diffColNum);
44,458,813✔
3683
  if (NULL == pRows) {
44,458,813✔
3684
    return terrno;
×
3685
  }
3686

3687
  bool keepNull = false;
44,458,813✔
3688
  for (int i = 0; i < diffColNum; ++i) {
88,940,792✔
3689
    SqlFunctionCtx* pCtx = *(SqlFunctionCtx**)taosArrayGet(pCtxArray, i);
44,481,979✔
3690
    if (NULL == pCtx) {
44,481,979✔
3691
      code = terrno;
×
3692
      goto _exit;
×
3693
    }
3694
    funcInputUpdate(pCtx);
44,481,979✔
3695
    SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
44,481,979✔
3696
    SDiffInfo*           pDiffInfo = GET_ROWCELL_INTERBUF(pResInfo);
44,481,979✔
3697
    if (!ignoreNull(pDiffInfo->ignoreOption)) {
44,481,979✔
3698
      keepNull = true;
44,464,390✔
3699
    }
3700
  }
3701

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

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

3765
  for (int i = 0; i < diffColNum; ++i) {
88,924,869✔
3766
    SqlFunctionCtx* pCtx = *(SqlFunctionCtx**)taosArrayGet(pCtxArray, i);
44,473,803✔
3767
    if (NULL == pCtx) {
44,473,803✔
3768
      code = terrno;
×
3769
      goto _exit;
×
3770
    }
3771
    SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
44,473,803✔
3772
    pResInfo->numOfRes = numOfElems;
44,473,803✔
3773
  }
3774

3775
_exit:
44,458,813✔
3776
  if (pRows) {
44,458,813✔
3777
    taosArrayDestroy(pRows);
44,458,813✔
3778
    pRows = NULL;
44,458,813✔
3779
  }
3780
  return code;
44,458,813✔
3781
}
3782

3783
bool getFillforwardFuncEnv(SFunctionNode* UNUSED_PARAM(pFunc), SFuncExecEnv* pEnv) {
35,335✔
3784
  pEnv->calcMemSize = sizeof(SFillforwardInfo);
35,335✔
3785
  return true;
35,335✔
3786
}
3787

3788
int32_t fillforwardFunctionSetup(SqlFunctionCtx* pCtx, SResultRowEntryInfo* pResInfo) {
73,196✔
3789
  if (pResInfo->initialized) {
73,196✔
3790
    return TSDB_CODE_SUCCESS;
35,335✔
3791
  }
3792
  if (TSDB_CODE_SUCCESS != functionSetup(pCtx, pResInfo)) {
37,861✔
3793
    return TSDB_CODE_FUNC_SETUP_ERROR;
×
3794
  }
3795
  SFillforwardInfo* pFillforwardInfo = GET_ROWCELL_INTERBUF(pResInfo);
37,861✔
3796
  pFillforwardInfo->nonnull = false;
37,861✔
3797

3798
  return TSDB_CODE_SUCCESS;
37,861✔
3799
}
3800

3801
int32_t fillforwardFunction(SqlFunctionCtx* pCtx) { return TSDB_CODE_SUCCESS; }
37,861✔
3802

3803
static int32_t doHandleFillforward(SFillforwardInfo* pFillforwardInfo, int32_t type, SColumnInfoData* pOutput, int32_t pos) {
122,816✔
3804
  if (!pFillforwardInfo->nonnull) {
122,816✔
3805
    colDataSetNULL(pOutput, pos);
13,893✔
3806

3807
    return TSDB_CODE_SUCCESS;
13,893✔
3808
  }
3809

3810
  switch (type) {
108,923✔
3811
    case TSDB_DATA_TYPE_BOOL:
52,509✔
3812
    case TSDB_DATA_TYPE_UTINYINT:
3813
    case TSDB_DATA_TYPE_TINYINT:
3814
    case TSDB_DATA_TYPE_USMALLINT:
3815
    case TSDB_DATA_TYPE_SMALLINT:
3816
    case TSDB_DATA_TYPE_UINT:
3817
    case TSDB_DATA_TYPE_INT:
3818
    case TSDB_DATA_TYPE_UBIGINT:
3819
    case TSDB_DATA_TYPE_BIGINT:
3820
    case TSDB_DATA_TYPE_TIMESTAMP:
3821
      colDataSetInt64(pOutput, pos, &pFillforwardInfo->v);
52,509✔
3822
      break;
52,509✔
3823
    case TSDB_DATA_TYPE_FLOAT:
20,208✔
3824
      colDataSetFloat(pOutput, pos, &pFillforwardInfo->fv);
20,208✔
3825
      break;
20,208✔
3826
    case TSDB_DATA_TYPE_DOUBLE:
22,734✔
3827
      colDataSetDouble(pOutput, pos, &pFillforwardInfo->dv);
22,734✔
3828
      break;
22,734✔
3829
    case TSDB_DATA_TYPE_DECIMAL64:
4,631✔
3830
      return colDataSetVal(pOutput, pos, (const char*)&pFillforwardInfo->v, false);
4,631✔
3831
    case TSDB_DATA_TYPE_DECIMAL:
×
3832
      return colDataSetVal(pOutput, pos, (void*)pFillforwardInfo->dec, false);
×
3833
    case TSDB_DATA_TYPE_VARCHAR:
8,841✔
3834
    case TSDB_DATA_TYPE_VARBINARY:
3835
    case TSDB_DATA_TYPE_NCHAR:
3836
      return colDataSetVal(pOutput, pos, (void*)pFillforwardInfo->str, false);
8,841✔
3837
    default:
×
3838
      return TSDB_CODE_FUNC_FUNTION_PARA_TYPE;
×
3839
  }
3840

3841
  return TSDB_CODE_SUCCESS;
95,451✔
3842
}
3843

3844
static int32_t setFillforwardResult(SqlFunctionCtx* pCtx, SFuncInputRow* pRow, int32_t pos) {
122,816✔
3845
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
122,816✔
3846
  SFillforwardInfo*            pFillforwardInfo = GET_ROWCELL_INTERBUF(pResInfo);
122,816✔
3847

3848
  SInputColumnInfoData* pInput = &pCtx->input;
122,816✔
3849
  SColumnInfoData*      pInputCol = pInput->pData[0];
122,816✔
3850
  int8_t                inputType = pInputCol->info.type;
122,816✔
3851
  SColumnInfoData*      pOutput = (SColumnInfoData*)pCtx->pOutput;
122,816✔
3852
  int32_t               code = TSDB_CODE_SUCCESS;
122,816✔
3853

3854
  code = doHandleFillforward(pFillforwardInfo, inputType, pOutput, pos);
122,816✔
3855
  if (code != TSDB_CODE_SUCCESS) {
122,816✔
3856
    return code;
×
3857
  }
3858

3859
  // handle selectivity
3860
  if (pCtx->subsidiaries.num > 0) {
122,816✔
3861
    code = appendSelectivityCols(pCtx, pRow->block, pRow->rowIndex, pos);
33,564✔
3862
    if (code != TSDB_CODE_SUCCESS) {
33,564✔
3863
      return code;
×
3864
    }
3865
  }
3866

3867
  return TSDB_CODE_SUCCESS;
122,816✔
3868
}
3869

3870
int32_t fillforwardFunctionByRow(SArray* pCtxArray) {
10,917✔
3871
  int32_t code = TSDB_CODE_SUCCESS;
10,917✔
3872
  int     fillforwardColNum = pCtxArray->size;
10,917✔
3873
  if (fillforwardColNum == 0) {
10,917✔
3874
    return TSDB_CODE_SUCCESS;
×
3875
  }
3876
  int32_t numOfElems = 0;
10,917✔
3877

3878
  SArray* pRows = taosArrayInit_s(sizeof(SFuncInputRow), fillforwardColNum);
10,917✔
3879
  if (NULL == pRows) {
10,917✔
3880
    return terrno;
×
3881
  }
3882

3883
  for (int i = 0; i < fillforwardColNum; ++i) {
48,778✔
3884
    SqlFunctionCtx* pCtx = *(SqlFunctionCtx**)taosArrayGet(pCtxArray, i);
37,861✔
3885
    if (NULL == pCtx) {
37,861✔
3886
      code = terrno;
×
3887
      goto _exit;
×
3888
    }
3889
    funcInputUpdate(pCtx);
37,861✔
3890
  }
3891

3892
  SqlFunctionCtx* pCtx0 = *(SqlFunctionCtx**)taosArrayGet(pCtxArray, 0);
10,917✔
3893
  SFuncInputRow*  pRow0 = (SFuncInputRow*)taosArrayGet(pRows, 0);
10,917✔
3894
  if (NULL == pCtx0 || NULL == pRow0) {
10,917✔
3895
    code = terrno;
×
3896
    goto _exit;
×
3897
  }
3898
  int32_t startOffset = pCtx0->offset;
10,917✔
3899
  bool    result = false;
10,917✔
3900
  while (1) {
33,564✔
3901
    code = funcInputGetNextRow(pCtx0, pRow0, &result);
44,481✔
3902
    if (TSDB_CODE_SUCCESS != code) {
44,481✔
3903
      goto _exit;
×
3904
    }
3905
    if (!result) {
44,481✔
3906
      break;
10,496✔
3907
    }
3908

3909
    for (int i = 1; i < fillforwardColNum; ++i) {
123,237✔
3910
      SqlFunctionCtx* pCtx = *(SqlFunctionCtx**)taosArrayGet(pCtxArray, i);
89,252✔
3911
      SFuncInputRow*  pRow = (SFuncInputRow*)taosArrayGet(pRows, i);
89,252✔
3912
      if (NULL == pCtx || NULL == pRow) {
89,252✔
3913
        code = terrno;
×
3914
        goto _exit;
×
3915
      }
3916
      code = funcInputGetNextRow(pCtx, pRow, &result);
89,252✔
3917
      if (TSDB_CODE_SUCCESS != code) {
89,252✔
3918
        goto _exit;
×
3919
      }
3920
      if (!result) {
89,252✔
3921
        // rows are not equal
3922
        code = TSDB_CODE_QRY_EXECUTOR_INTERNAL_ERROR;
×
3923
        goto _exit;
×
3924
      }
3925
    }
3926

3927
    int32_t pos = startOffset + numOfElems;
33,985✔
3928

3929
    for (int i = 0; i < fillforwardColNum; ++i) {
156,801✔
3930
      SqlFunctionCtx* pCtx = *(SqlFunctionCtx**)taosArrayGet(pCtxArray, i);
123,237✔
3931
      SFuncInputRow*  pRow = (SFuncInputRow*)taosArrayGet(pRows, i);
123,237✔
3932
      if (NULL == pCtx || NULL == pRow) {
123,237✔
3933
        code = terrno;
×
3934
        goto _exit;
×
3935
      }
3936

3937
      if (!colDataIsNull_s(pCtx->input.pData[0], pCtx->rowIter.rowIndex - 1)) {
246,474✔
3938
        SResultRowEntryInfo*  pResInfo = GET_RES_INFO(pCtx);
75,664✔
3939
        SFillforwardInfo*             pFillforwardInfo = GET_ROWCELL_INTERBUF(pResInfo);
75,664✔
3940
        SInputColumnInfoData* pInput = &pCtx->input;
75,664✔
3941
        SColumnInfoData*      pInputCol = pInput->pData[0];
75,664✔
3942
        int8_t                inputType = pInputCol->info.type;
75,664✔
3943

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

3989
            (void)memcpy(pFillforwardInfo->str, pv, varDataTLen(pv));
3,789✔
3990
          } break;
3,789✔
3991
          default: {
421✔
3992
            code = TSDB_CODE_FUNC_FUNTION_PARA_TYPE;
421✔
3993
            goto _exit;
421✔
3994
          }
3995
        }
3996

3997
        if (!pFillforwardInfo->nonnull) {
75,243✔
3998
          pFillforwardInfo->nonnull = true;
37,019✔
3999
        }
4000
      }
4001

4002
      code = setFillforwardResult(pCtx, pRow, pos);
122,816✔
4003
      if (code) {
122,816✔
4004
        goto _exit;
×
4005
      }
4006
    }
4007

4008
    ++numOfElems;
33,564✔
4009
  }
4010

4011
_exit:
10,917✔
4012
  for (int i = 0; i < fillforwardColNum; ++i) {
48,778✔
4013
    SqlFunctionCtx* pCtx = *(SqlFunctionCtx**)taosArrayGet(pCtxArray, i);
37,861✔
4014
    if (!pCtx) {
37,861✔
4015
      break;
×
4016
    }
4017

4018
    SResultRowEntryInfo*  pResInfo = GET_RES_INFO(pCtx);
37,861✔
4019
    SFillforwardInfo*             pRes = GET_ROWCELL_INTERBUF(pResInfo);
37,861✔
4020
    SInputColumnInfoData* pInput = &pCtx->input;
37,861✔
4021
    SColumnInfoData*      pInputCol = pInput->pData[0];
37,861✔
4022

4023
    if (IS_VAR_DATA_TYPE(pInputCol->info.type) && pRes->nonnull) {
37,861✔
4024
      taosMemoryFree(pRes->str);
2,526✔
4025
    }
4026

4027
    if (!code) {
37,861✔
4028
      pResInfo->numOfRes = numOfElems;
37,440✔
4029
    }
4030
  }
4031

4032
  if (pRows) {
10,917✔
4033
    taosArrayDestroy(pRows);
10,917✔
4034
    pRows = NULL;
10,917✔
4035
  }
4036
  return code;
10,917✔
4037
}
4038

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

4041
bool getTopBotFuncEnv(SFunctionNode* pFunc, SFuncExecEnv* pEnv) {
2,177,397✔
4042
  SValueNode* pkNode = (SValueNode*)nodesListGetNode(pFunc->pParameterList, 1);
2,177,397✔
4043
  pEnv->calcMemSize = sizeof(STopBotRes) + pkNode->datum.i * sizeof(STopBotResItem);
2,177,450✔
4044
  return true;
2,177,038✔
4045
}
4046

4047
int32_t topBotFunctionSetup(SqlFunctionCtx* pCtx, SResultRowEntryInfo* pResInfo) {
7,858,831✔
4048
  if (pResInfo->initialized) {
7,858,831✔
4049
    return TSDB_CODE_SUCCESS;
×
4050
  }
4051
  if (TSDB_CODE_SUCCESS != functionSetup(pCtx, pResInfo)) {
7,858,831✔
4052
    return TSDB_CODE_FUNC_SETUP_ERROR;
×
4053
  }
4054

4055
  STopBotRes*           pRes = GET_ROWCELL_INTERBUF(pResInfo);
7,856,914✔
4056
  SInputColumnInfoData* pInput = &pCtx->input;
7,858,060✔
4057

4058
  pRes->maxSize = pCtx->param[1].param.i;
7,858,060✔
4059

4060
  pRes->nullTupleSaved = false;
7,859,347✔
4061
  pRes->nullTuplePos.pageId = -1;
7,859,759✔
4062
  return TSDB_CODE_SUCCESS;
7,857,318✔
4063
}
4064

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

4070
  return pRes;
2,147,483,647✔
4071
}
4072

4073
static int32_t doAddIntoResult(SqlFunctionCtx* pCtx, void* pData, int32_t rowIndex, SSDataBlock* pSrcBlock,
4074
                               uint16_t type, uint64_t uid, SResultRowEntryInfo* pEntryInfo, bool isTopQuery);
4075

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

4078
int32_t topFunction(SqlFunctionCtx* pCtx) {
8,747,246✔
4079
  int32_t              numOfElems = 0;
8,747,246✔
4080
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
8,747,246✔
4081

4082
  SInputColumnInfoData* pInput = &pCtx->input;
8,747,246✔
4083
  SColumnInfoData*      pCol = pInput->pData[0];
8,745,934✔
4084

4085
  STopBotRes* pRes = getTopBotOutputInfo(pCtx);
8,746,038✔
4086
  pRes->type = pInput->pData[0]->info.type;
8,747,482✔
4087

4088
  int32_t start = pInput->startRowIndex;
8,748,278✔
4089
  for (int32_t i = start; i < pInput->numOfRows + start; ++i) {
2,147,483,647✔
4090
    if (pCol->hasNull && colDataIsNull_f(pCol, i)) {
2,147,483,647✔
4091
      continue;
1,205,005✔
4092
    }
4093

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

4102
  if (numOfElems == 0 && pCtx->subsidiaries.num > 0 && !pRes->nullTupleSaved) {
8,749,722✔
4103
    int32_t code = saveTupleData(pCtx, pInput->startRowIndex, pCtx->pSrcBlock, &pRes->nullTuplePos);
6,618✔
4104
    if (code != TSDB_CODE_SUCCESS) {
6,618✔
4105
      return code;
×
4106
    }
4107
    pRes->nullTupleSaved = true;
6,618✔
4108
  }
4109
  return TSDB_CODE_SUCCESS;
8,749,310✔
4110
}
4111

4112
int32_t bottomFunction(SqlFunctionCtx* pCtx) {
3,141,459✔
4113
  int32_t              numOfElems = 0;
3,141,459✔
4114
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
3,141,459✔
4115

4116
  SInputColumnInfoData* pInput = &pCtx->input;
3,141,459✔
4117
  SColumnInfoData*      pCol = pInput->pData[0];
3,140,921✔
4118

4119
  STopBotRes* pRes = getTopBotOutputInfo(pCtx);
3,140,921✔
4120
  pRes->type = pInput->pData[0]->info.type;
3,140,921✔
4121

4122
  int32_t start = pInput->startRowIndex;
3,141,459✔
4123
  for (int32_t i = start; i < pInput->numOfRows + start; ++i) {
1,850,980,594✔
4124
    if (pCol->hasNull && colDataIsNull_f(pCol, i)) {
1,847,856,589✔
4125
      continue;
2,152,527✔
4126
    }
4127

4128
    numOfElems++;
1,846,180,711✔
4129
    char*   data = colDataGetData(pCol, i);
1,846,180,711✔
4130
    int32_t code = doAddIntoResult(pCtx, data, i, pCtx->pSrcBlock, pRes->type, pInput->uid, pResInfo, false);
1,846,095,640✔
4131
    if (code != TSDB_CODE_SUCCESS) {
1,845,686,608✔
4132
      return code;
×
4133
    }
4134
  }
4135

4136
  if (numOfElems == 0 && pCtx->subsidiaries.num > 0 && !pRes->nullTupleSaved) {
3,141,459✔
4137
    int32_t code = saveTupleData(pCtx, pInput->startRowIndex, pCtx->pSrcBlock, &pRes->nullTuplePos);
9,156✔
4138
    if (code != TSDB_CODE_SUCCESS) {
9,156✔
4139
      return code;
×
4140
    }
4141
    pRes->nullTupleSaved = true;
9,156✔
4142
  }
4143

4144
  return TSDB_CODE_SUCCESS;
3,141,459✔
4145
}
4146

4147
static int32_t topBotResComparFn(const void* p1, const void* p2, const void* param) {
494,658,525✔
4148
  uint16_t type = *(uint16_t*)param;
494,658,525✔
4149

4150
  STopBotResItem* val1 = (STopBotResItem*)p1;
494,657,184✔
4151
  STopBotResItem* val2 = (STopBotResItem*)p2;
494,657,184✔
4152

4153
  if (IS_SIGNED_NUMERIC_TYPE(type)) {
494,657,184✔
4154
    if (val1->v.i == val2->v.i) {
313,149,914✔
4155
      return 0;
61,432,527✔
4156
    }
4157

4158
    return (val1->v.i > val2->v.i) ? 1 : -1;
252,263,970✔
4159
  } else if (IS_UNSIGNED_NUMERIC_TYPE(type)) {
181,507,270✔
4160
    if (val1->v.u == val2->v.u) {
90,703,947✔
4161
      return 0;
19,513,413✔
4162
    }
4163

4164
    return (val1->v.u > val2->v.u) ? 1 : -1;
71,375,270✔
4165
  } else if (TSDB_DATA_TYPE_FLOAT == type) {
90,803,497✔
4166
    if (val1->v.f == val2->v.f) {
5,356,165✔
4167
      return 0;
26,775✔
4168
    }
4169

4170
    return (val1->v.f > val2->v.f) ? 1 : -1;
5,329,390✔
4171
  }
4172

4173
  if (val1->v.d == val2->v.d) {
85,447,332✔
4174
    return 0;
4,675✔
4175
  }
4176

4177
  return (val1->v.d > val2->v.d) ? 1 : -1;
85,498,595✔
4178
}
4179

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

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

4188
  STopBotResItem* pItems = pRes->pItems;
2,147,483,647✔
4189

4190
  // not full yet
4191
  if (pEntryInfo->numOfRes < pRes->maxSize) {
2,147,483,647✔
4192
    STopBotResItem* pItem = &pItems[pEntryInfo->numOfRes];
45,531,447✔
4193
    pItem->v = val;
45,531,825✔
4194
    pItem->uid = uid;
45,533,030✔
4195

4196
    // save the data of this tuple
4197
    if (pCtx->subsidiaries.num > 0) {
45,535,481✔
4198
      code = saveTupleData(pCtx, rowIndex, pSrcBlock, &pItem->tuplePos);
11,577,106✔
4199
      if (code != TSDB_CODE_SUCCESS) {
11,574,906✔
4200
        return code;
×
4201
      }
4202
    }
4203
#ifdef BUF_PAGE_DEBUG
4204
    qDebug("page_saveTuple i:%d, item:%p,pageId:%d, offset:%d\n", pEntryInfo->numOfRes, pItem, pItem->tuplePos.pageId,
4205
           pItem->tuplePos.offset);
4206
#endif
4207
    // allocate the buffer and keep the data of this row into the new allocated buffer
4208
    pEntryInfo->numOfRes++;
45,532,314✔
4209
    code = taosheapsort((void*)pItems, sizeof(STopBotResItem), pEntryInfo->numOfRes, (const void*)&type,
45,532,500✔
4210
                        topBotResComparFn, !isTopQuery);
45,532,976✔
4211
    if (code != TSDB_CODE_SUCCESS) {
45,533,373✔
4212
      return code;
×
4213
    }
4214
  } else {  // replace the minimum value in the result
4215
    if ((isTopQuery && ((IS_SIGNED_NUMERIC_TYPE(type) && val.i > pItems[0].v.i) ||
2,147,483,647✔
4216
                        (IS_UNSIGNED_NUMERIC_TYPE(type) && val.u > pItems[0].v.u) ||
2,147,483,647✔
4217
                        (TSDB_DATA_TYPE_FLOAT == type && val.f > pItems[0].v.f) ||
2,147,483,647✔
4218
                        (TSDB_DATA_TYPE_DOUBLE == type && val.d > pItems[0].v.d))) ||
2,147,483,647✔
4219
        (!isTopQuery && ((IS_SIGNED_NUMERIC_TYPE(type) && val.i < pItems[0].v.i) ||
2,147,483,647✔
4220
                         (IS_UNSIGNED_NUMERIC_TYPE(type) && val.u < pItems[0].v.u) ||
1,833,916,030✔
4221
                         (TSDB_DATA_TYPE_FLOAT == type && val.f < pItems[0].v.f) ||
1,832,253,951✔
4222
                         (TSDB_DATA_TYPE_DOUBLE == type && val.d < pItems[0].v.d)))) {
1,832,184,961✔
4223
      // replace the old data and the coresponding tuple data
4224
      STopBotResItem* pItem = &pItems[0];
37,617,217✔
4225
      pItem->v = val;
37,617,217✔
4226
      pItem->uid = uid;
37,379,374✔
4227

4228
      // save the data of this tuple by over writing the old data
4229
      if (pCtx->subsidiaries.num > 0) {
37,379,270✔
4230
        code = updateTupleData(pCtx, rowIndex, pSrcBlock, &pItem->tuplePos);
18,656,798✔
4231
        if (code != TSDB_CODE_SUCCESS) {
18,657,210✔
4232
          return code;
×
4233
        }
4234
      }
4235
#ifdef BUF_PAGE_DEBUG
4236
      qDebug("page_copyTuple pageId:%d, offset:%d", pItem->tuplePos.pageId, pItem->tuplePos.offset);
4237
#endif
4238
      code = taosheapadjust((void*)pItems, sizeof(STopBotResItem), 0, pEntryInfo->numOfRes - 1, (const void*)&type,
37,377,771✔
4239
                            topBotResComparFn, NULL, !isTopQuery);
37,379,166✔
4240
      if (code != TSDB_CODE_SUCCESS) {
37,371,452✔
4241
        return code;
×
4242
      }
4243
    }
4244
  }
4245

4246
  return TSDB_CODE_SUCCESS;
2,147,483,647✔
4247
}
4248

4249

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

4255
  if (!pData->hasNull) {
×
4256
    return false;
×
4257
  }
4258

4259
  int64_t endIdx = startIdx + rows;
×
4260
  for (int64_t i = startIdx; i < endIdx; ++i) {
×
4261
    if (colDataIsNull_s(pData, i)) {
×
4262
      return true;
×
4263
    }
4264
  }
4265

4266
  return false;
×
4267
}
4268

4269

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

4281
  int32_t offset = 0;
109,723,824✔
4282
  for (int32_t i = 0; i < pSubsidiaryies->num; ++i) {
346,735,231✔
4283
    SqlFunctionCtx* pc = pSubsidiaryies->pCtx[i];
237,014,055✔
4284

4285
    // group_key function has its own process function
4286
    // do not process there
4287
    if (fmIsGroupKeyFunc(pc->functionId)) {
237,012,660✔
4288
      continue;
×
4289
    }
4290

4291
    if (fmIsSelectValueFunc(pc->functionId)) {
237,009,135✔
4292
      SFunctParam* pFuncParam = &pc->pExpr->base.pParam[0];
237,008,753✔
4293
      int32_t      srcSlotId = pFuncParam->pCol->slotId;
237,011,857✔
4294

4295
      SColumnInfoData* pCol = taosArrayGet(pSrcBlock->pDataBlock, srcSlotId);
237,008,445✔
4296
      if (NULL == pCol) {
237,013,041✔
4297
        return TSDB_CODE_OUT_OF_RANGE;
×
4298
      }
4299
      if ((nullList[i] = colDataIsNull_s(pCol, rowIndex)) == true) {
474,025,004✔
4300
        offset += pCol->info.bytes;
63,758,732✔
4301
        continue;
63,758,732✔
4302
      }
4303

4304
      char* p = colDataGetData(pCol, rowIndex);
173,250,154✔
4305
      if (IS_VAR_DATA_TYPE(pCol->info.type)) {
173,252,898✔
4306
        int32_t bytes = calcStrBytesByType(pCol->info.type, p);
8,622,588✔
4307
        (void)memcpy(pStart + offset, p, bytes);
8,625,036✔
4308
      } else {
4309
        (void)memcpy(pStart + offset, p, pCol->info.bytes);
164,626,637✔
4310
      }
4311

4312
      offset += pCol->info.bytes;
173,252,488✔
4313
      continue;
173,253,295✔
4314
    }
4315
  }
4316

4317
  *res = buf;
109,716,613✔
4318
  return TSDB_CODE_SUCCESS;
109,722,893✔
4319
}
4320

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

4327
    if (pHandle->currentPage == -1) {
2,147,483,647✔
4328
      pPage = getNewBufPage(pHandle->pBuf, &pHandle->currentPage);
5,396,503✔
4329
      if (pPage == NULL) {
5,396,915✔
4330
        return terrno;
×
4331
      }
4332
      pPage->num = sizeof(SFilePage);
5,396,915✔
4333
    } else {
4334
      pPage = getBufPage(pHandle->pBuf, pHandle->currentPage);
2,147,483,647✔
4335
      if (pPage == NULL) {
2,147,483,647✔
4336
        return terrno;
×
4337
      }
4338
      if (pPage->num + length > getBufPageSize(pHandle->pBuf)) {
2,147,483,647✔
4339
        // current page is all used, let's prepare a new buffer page
4340
        releaseBufPage(pHandle->pBuf, pPage);
3,290,958✔
4341
        pPage = getNewBufPage(pHandle->pBuf, &pHandle->currentPage);
3,290,958✔
4342
        if (pPage == NULL) {
3,290,958✔
4343
          return terrno;
×
4344
        }
4345
        pPage->num = sizeof(SFilePage);
3,290,958✔
4346
      }
4347
    }
4348

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

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

4361
  *pPos = p;
2,147,483,647✔
4362
  return TSDB_CODE_SUCCESS;
2,147,483,647✔
4363
}
4364

4365
int32_t saveTupleData(SqlFunctionCtx* pCtx, int32_t rowIndex, const SSDataBlock* pSrcBlock, STuplePos* pPos) {
72,842,942✔
4366
  int32_t code = prepareBuf(pCtx);
72,842,942✔
4367
  if (TSDB_CODE_SUCCESS != code) {
72,842,069✔
4368
    return code;
×
4369
  }
4370

4371
  SWinKey key = {0};
72,842,069✔
4372
  if (pCtx->saveHandle.pBuf == NULL) {
72,843,138✔
4373
    SColumnInfoData* pColInfo = taosArrayGet(pSrcBlock->pDataBlock, pCtx->saveHandle.pState->tsIndex);
×
4374
    if (NULL == pColInfo) {
×
4375
      return TSDB_CODE_OUT_OF_RANGE;
×
4376
    }
4377
    if (pColInfo->info.type != TSDB_DATA_TYPE_TIMESTAMP) {
×
4378
      return TSDB_CODE_FUNC_FUNTION_PARA_TYPE;
×
4379
    }
4380
    key.groupId = pSrcBlock->info.id.groupId;
×
4381
    key.ts = *(int64_t*)colDataGetData(pColInfo, rowIndex);
×
4382
    key.numInGroup = pCtx->pExpr->pExpr->_function.bindExprID;
×
4383
  }
4384

4385
  char* buf = NULL;
72,843,971✔
4386
  code = serializeTupleData(pCtx, pSrcBlock, rowIndex, &pCtx->subsidiaries, pCtx->subsidiaries.buf, &buf);
72,842,902✔
4387
  if (TSDB_CODE_SUCCESS != code) {
72,838,413✔
4388
    return code;
×
4389
  }
4390
  return doSaveTupleData(&pCtx->saveHandle, buf, pCtx->subsidiaries.rowLen, &key, pPos, pCtx->pStore);
72,838,413✔
4391
}
4392

4393
static int32_t doUpdateTupleData(SSerializeDataHandle* pHandle, const void* pBuf, size_t length, STuplePos* pPos,
36,884,235✔
4394
                                 SFunctionStateStore* pStore) {
4395
  if (pHandle->pBuf != NULL) {
36,884,235✔
4396
    SFilePage* pPage = getBufPage(pHandle->pBuf, pPos->pageId);
36,884,647✔
4397
    if (pPage == NULL) {
36,884,647✔
4398
      return terrno;
×
4399
    }
4400
    (void)memcpy(pPage->data + pPos->offset, pBuf, length);
36,884,647✔
4401
    setBufPageDirty(pPage, true);
36,883,823✔
4402
    releaseBufPage(pHandle->pBuf, pPage);
36,883,303✔
4403
  } else {
4404
    int32_t code = pStore->streamStateFuncPut(pHandle->pState, &pPos->streamTupleKey, pBuf, length);
×
4405
    if (TSDB_CODE_SUCCESS != code) {
×
4406
      return code;
×
4407
    }
4408
  }
4409

4410
  return TSDB_CODE_SUCCESS;
36,883,407✔
4411
}
4412

4413
int32_t updateTupleData(SqlFunctionCtx* pCtx, int32_t rowIndex, const SSDataBlock* pSrcBlock, STuplePos* pPos) {
36,884,235✔
4414
  int32_t code = prepareBuf(pCtx);
36,884,235✔
4415
  if (TSDB_CODE_SUCCESS != code) {
36,883,823✔
4416
    return code;
×
4417
  }
4418

4419
  char* buf = NULL;
36,883,823✔
4420
  code = serializeTupleData(pCtx, pSrcBlock, rowIndex, &pCtx->subsidiaries, pCtx->subsidiaries.buf, &buf);
36,883,823✔
4421
  if (TSDB_CODE_SUCCESS != code) {
36,884,647✔
4422
    return code;
×
4423
  }
4424
  return doUpdateTupleData(&pCtx->saveHandle, buf, pCtx->subsidiaries.rowLen, pPos, pCtx->pStore);
36,884,647✔
4425
}
4426

4427
static int32_t doLoadTupleData(SSerializeDataHandle* pHandle, const STuplePos* pPos, SFunctionStateStore* pStore,
72,926,134✔
4428
                               char** value) {
4429
  if (pHandle->pBuf != NULL) {
72,926,134✔
4430
    SFilePage* pPage = getBufPage(pHandle->pBuf, pPos->pageId);
72,928,105✔
4431
    if (pPage == NULL) {
72,926,185✔
4432
      *value = NULL;
×
4433
      return terrno;
×
4434
    }
4435
    *value = pPage->data + pPos->offset;
72,926,185✔
4436
    releaseBufPage(pHandle->pBuf, pPage);
72,927,263✔
4437
    return TSDB_CODE_SUCCESS;
72,927,263✔
4438
  } else {
UNCOV
4439
    *value = NULL;
×
4440
    int32_t vLen;
×
4441
    int32_t code = pStore->streamStateFuncGet(pHandle->pState, &pPos->streamTupleKey, (void**)(value), &vLen);
×
4442
    if (TSDB_CODE_SUCCESS != code) {
×
4443
      return code;
×
4444
    }
4445
    return TSDB_CODE_SUCCESS;
×
4446
  }
4447
}
4448

4449
int32_t loadTupleData(SqlFunctionCtx* pCtx, const STuplePos* pPos, char** value) {
72,926,134✔
4450
  return doLoadTupleData(&pCtx->saveHandle, pPos, pCtx->pStore, value);
72,926,134✔
4451
}
4452

4453
int32_t topBotFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
7,849,817✔
4454
  int32_t code = TSDB_CODE_SUCCESS;
7,849,817✔
4455

4456
  SResultRowEntryInfo* pEntryInfo = GET_RES_INFO(pCtx);
7,849,817✔
4457
  STopBotRes*          pRes = getTopBotOutputInfo(pCtx);
7,849,817✔
4458

4459
  int16_t type = pCtx->pExpr->base.resSchema.type;
7,847,753✔
4460
  int32_t slotId = pCtx->pExpr->base.resSchema.slotId;
7,847,753✔
4461

4462
  SColumnInfoData* pCol = taosArrayGet(pBlock->pDataBlock, slotId);
7,847,753✔
4463
  if (NULL == pCol) {
7,849,301✔
4464
    return TSDB_CODE_OUT_OF_RANGE;
×
4465
  }
4466

4467
  // todo assign the tag value and the corresponding row data
4468
  int32_t currentRow = pBlock->info.rows;
7,849,301✔
4469
  if (pEntryInfo->numOfRes <= 0) {
7,849,301✔
4470
    colDataSetNULL(pCol, currentRow);
36,624✔
4471
    code = setSelectivityValue(pCtx, pBlock, &pRes->nullTuplePos, currentRow);
36,624✔
4472
    return code;
36,624✔
4473
  }
4474
  for (int32_t i = 0; i < pEntryInfo->numOfRes; ++i) {
53,345,459✔
4475
    STopBotResItem* pItem = &pRes->pItems[i];
45,514,722✔
4476
    code = colDataSetVal(pCol, currentRow, (const char*)&pItem->v.i, false);
45,519,882✔
4477
    if (TSDB_CODE_SUCCESS != code) {
45,529,686✔
4478
      return code;
×
4479
    }
4480
#ifdef BUF_PAGE_DEBUG
4481
    qDebug("page_finalize i:%d,item:%p,pageId:%d, offset:%d\n", i, pItem, pItem->tuplePos.pageId,
4482
           pItem->tuplePos.offset);
4483
#endif
4484
    code = setSelectivityValue(pCtx, pBlock, &pRes->pItems[i].tuplePos, currentRow);
45,529,686✔
4485
    if (TSDB_CODE_SUCCESS != code) {
45,532,266✔
4486
      return code;
×
4487
    }
4488
    currentRow += 1;
45,532,266✔
4489
  }
4490

4491
  return code;
7,813,709✔
4492
}
4493

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

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

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

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

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

4567
int32_t getSpreadInfoSize() { return (int32_t)sizeof(SSpreadInfo); }
8,532,382✔
4568

4569
bool getSpreadFuncEnv(SFunctionNode* UNUSED_PARAM(pFunc), SFuncExecEnv* pEnv) {
4,155,265✔
4570
  pEnv->calcMemSize = sizeof(SSpreadInfo);
4,155,265✔
4571
  return true;
4,155,265✔
4572
}
4573

4574
int32_t spreadFunctionSetup(SqlFunctionCtx* pCtx, SResultRowEntryInfo* pResultInfo) {
100,920,984✔
4575
  if (pResultInfo->initialized) {
100,920,984✔
4576
    return TSDB_CODE_SUCCESS;
×
4577
  }
4578
  if (TSDB_CODE_SUCCESS != functionSetup(pCtx, pResultInfo)) {
100,920,984✔
4579
    return TSDB_CODE_FUNC_SETUP_ERROR;
×
4580
  }
4581

4582
  SSpreadInfo* pInfo = GET_ROWCELL_INTERBUF(pResultInfo);
100,921,416✔
4583
  SET_DOUBLE_VAL(&pInfo->min, DBL_MAX);
100,921,500✔
4584
  SET_DOUBLE_VAL(&pInfo->max, -DBL_MAX);
100,921,939✔
4585
  pInfo->hasResult = false;
100,919,858✔
4586
  return TSDB_CODE_SUCCESS;
100,920,380✔
4587
}
4588

4589
int32_t spreadFunction(SqlFunctionCtx* pCtx) {
152,510,103✔
4590
  int32_t numOfElems = 0;
152,510,103✔
4591

4592
  // Only the pre-computing information loaded and actual data does not loaded
4593
  SInputColumnInfoData* pInput = &pCtx->input;
152,510,103✔
4594
  SColumnDataAgg*       pAgg = pInput->pColumnDataAgg[0];
152,515,566✔
4595
  int32_t               type = pInput->pData[0]->info.type;
152,538,148✔
4596

4597
  SSpreadInfo* pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
152,538,113✔
4598

4599
  if (pInput->colDataSMAIsSet) {
152,526,892✔
4600
    numOfElems = pInput->numOfRows - pAgg->numOfNull;
44,565,830✔
4601
    if (numOfElems == 0) {
44,567,013✔
4602
      goto _spread_over;
31,613,860✔
4603
    }
4604
    double tmin = 0.0, tmax = 0.0;
12,953,153✔
4605
    if (IS_SIGNED_NUMERIC_TYPE(type) || IS_TIMESTAMP_TYPE(type)) {
12,953,153✔
4606
      tmin = (double)GET_INT64_VAL(&pAgg->min);
6,627,511✔
4607
      tmax = (double)GET_INT64_VAL(&pAgg->max);
6,626,903✔
4608
    } else if (IS_FLOAT_TYPE(type)) {
6,325,642✔
4609
      tmin = GET_DOUBLE_VAL(&pAgg->min);
×
4610
      tmax = GET_DOUBLE_VAL(&pAgg->max);
×
4611
    } else if (IS_UNSIGNED_NUMERIC_TYPE(type)) {
6,325,653✔
4612
      tmin = (double)GET_UINT64_VAL(&pAgg->min);
6,325,045✔
4613
      tmax = (double)GET_UINT64_VAL(&pAgg->max);
6,325,642✔
4614
    }
4615

4616
    if (GET_DOUBLE_VAL(&pInfo->min) > tmin) {
12,952,567✔
4617
      SET_DOUBLE_VAL(&pInfo->min, tmin);
590,563✔
4618
    }
4619

4620
    if (GET_DOUBLE_VAL(&pInfo->max) < tmax) {
12,951,959✔
4621
      SET_DOUBLE_VAL(&pInfo->max, tmax);
626,570✔
4622
    }
4623

4624
  } else {  // computing based on the true data block
4625
    SColumnInfoData* pCol = pInput->pData[0];
107,951,910✔
4626

4627
    int32_t start = pInput->startRowIndex;
107,961,450✔
4628
    // check the valid data one by one
4629
    for (int32_t i = start; i < pInput->numOfRows + start; ++i) {
2,147,483,647✔
4630
      if (colDataIsNull_f(pCol, i)) {
2,147,483,647✔
4631
        continue;
2,147,483,647✔
4632
      }
4633

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

4636
      double v = 0;
2,147,483,647✔
4637
      GET_TYPED_DATA(v, double, type, data, typeGetTypeModFromColInfo(&pCol->info));
2,147,483,647✔
4638
      if (v < GET_DOUBLE_VAL(&pInfo->min)) {
2,147,483,647✔
4639
        SET_DOUBLE_VAL(&pInfo->min, v);
98,040,848✔
4640
      }
4641

4642
      if (v > GET_DOUBLE_VAL(&pInfo->max)) {
2,147,483,647✔
4643
        SET_DOUBLE_VAL(&pInfo->max, v);
126,107,972✔
4644
      }
4645

4646
      numOfElems += 1;
2,147,483,647✔
4647
    }
4648
  }
4649

4650
_spread_over:
107,933,775✔
4651
  // data in the check operation are all null, not output
4652
  SET_VAL(GET_RES_INFO(pCtx), numOfElems, 1);
152,500,191✔
4653
  if (numOfElems > 0) {
152,524,308✔
4654
    pInfo->hasResult = true;
112,149,564✔
4655
  }
4656

4657
  return TSDB_CODE_SUCCESS;
152,479,240✔
4658
}
4659

4660
static void spreadTransferInfo(SSpreadInfo* pInput, SSpreadInfo* pOutput) {
7,536,554✔
4661
  pOutput->hasResult = pInput->hasResult;
7,536,554✔
4662
  if (pInput->max > pOutput->max) {
7,536,554✔
4663
    pOutput->max = pInput->max;
5,309,743✔
4664
  }
4665

4666
  if (pInput->min < pOutput->min) {
7,536,554✔
4667
    pOutput->min = pInput->min;
5,306,171✔
4668
  }
4669
}
7,536,554✔
4670

4671
int32_t spreadFunctionMerge(SqlFunctionCtx* pCtx) {
6,063,247✔
4672
  SInputColumnInfoData* pInput = &pCtx->input;
6,063,247✔
4673
  SColumnInfoData*      pCol = pInput->pData[0];
6,063,247✔
4674

4675
  if (IS_NULL_TYPE(pCol->info.type)) {
6,063,247✔
4676
    SET_VAL(GET_RES_INFO(pCtx), 0, 1);
×
4677
    return TSDB_CODE_SUCCESS;
×
4678
  }
4679

4680
  if (pCol->info.type != TSDB_DATA_TYPE_BINARY) {
6,063,247✔
4681
    return TSDB_CODE_FUNC_FUNTION_PARA_TYPE;
×
4682
  }
4683

4684
  SSpreadInfo* pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
6,063,247✔
4685

4686
  int32_t start = pInput->startRowIndex;
6,063,247✔
4687
  for (int32_t i = start; i < start + pInput->numOfRows; ++i) {
14,239,120✔
4688
    if (colDataIsNull_s(pCol, i)) continue;
16,351,746✔
4689
    char*        data = colDataGetData(pCol, i);
8,175,873✔
4690
    SSpreadInfo* pInputInfo = (SSpreadInfo*)varDataVal(data);
8,175,873✔
4691
    if (pInputInfo->hasResult) {
8,175,873✔
4692
      spreadTransferInfo(pInputInfo, pInfo);
7,536,554✔
4693
    }
4694
  }
4695

4696
  if (pInfo->hasResult) {
6,063,247✔
4697
    GET_RES_INFO(pCtx)->numOfRes = 1;
5,700,943✔
4698
  }
4699

4700
  return TSDB_CODE_SUCCESS;
6,063,247✔
4701
}
4702

4703
int32_t spreadFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
85,495,413✔
4704
  SSpreadInfo* pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
85,495,413✔
4705
  if (pInfo->hasResult == true) {
85,495,413✔
4706
    SET_DOUBLE_VAL(&pInfo->result, pInfo->max - pInfo->min);
79,985,427✔
4707
  } else {
4708
    GET_RES_INFO(pCtx)->isNullRes = 1;
5,509,986✔
4709
  }
4710
  return functionFinalize(pCtx, pBlock);
85,495,413✔
4711
}
4712

4713
int32_t spreadPartialFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
8,189,229✔
4714
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
8,189,229✔
4715
  SSpreadInfo*         pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
8,189,229✔
4716
  int32_t              resultBytes = getSpreadInfoSize();
8,189,229✔
4717
  char*                res = taosMemoryCalloc(resultBytes + VARSTR_HEADER_SIZE, sizeof(char));
8,189,229✔
4718

4719
  if (NULL == res) {
8,189,229✔
4720
    return terrno;
×
4721
  }
4722
  (void)memcpy(varDataVal(res), pInfo, resultBytes);
8,189,229✔
4723
  varDataSetLen(res, resultBytes);
8,189,229✔
4724

4725
  int32_t          slotId = pCtx->pExpr->base.resSchema.slotId;
8,189,229✔
4726
  int32_t          code = TSDB_CODE_SUCCESS;
8,189,229✔
4727
  SColumnInfoData* pCol = taosArrayGet(pBlock->pDataBlock, slotId);
8,189,229✔
4728
  if (NULL == pCol) {
8,189,229✔
4729
    code = terrno;
×
4730
    goto _exit;
×
4731
  }
4732

4733
  code = colDataSetVal(pCol, pBlock->info.rows, res, false);
8,189,229✔
4734
  if (TSDB_CODE_SUCCESS != code) {
8,189,229✔
4735
    goto _exit;
×
4736
  }
4737

4738
_exit:
8,189,229✔
4739
  taosMemoryFree(res);
8,189,229✔
4740
  return code;
8,189,229✔
4741
}
4742

4743
int32_t spreadCombine(SqlFunctionCtx* pDestCtx, SqlFunctionCtx* pSourceCtx) {
×
4744
  SResultRowEntryInfo* pDResInfo = GET_RES_INFO(pDestCtx);
×
4745
  SSpreadInfo*         pDBuf = GET_ROWCELL_INTERBUF(pDResInfo);
×
4746

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

4755
int32_t getElapsedInfoSize() { return (int32_t)sizeof(SElapsedInfo); }
×
4756

4757
bool getElapsedFuncEnv(SFunctionNode* UNUSED_PARAM(pFunc), SFuncExecEnv* pEnv) {
2,340,645✔
4758
  pEnv->calcMemSize = sizeof(SElapsedInfo);
2,340,645✔
4759
  return true;
2,341,391✔
4760
}
4761

4762
int32_t elapsedFunctionSetup(SqlFunctionCtx* pCtx, SResultRowEntryInfo* pResultInfo) {
4,503,789✔
4763
  if (pResultInfo->initialized) {
4,503,789✔
4764
    return TSDB_CODE_SUCCESS;
×
4765
  }
4766
  if (TSDB_CODE_SUCCESS != functionSetup(pCtx, pResultInfo)) {
4,503,789✔
4767
    return TSDB_CODE_FUNC_SETUP_ERROR;
×
4768
  }
4769

4770
  SElapsedInfo* pInfo = GET_ROWCELL_INTERBUF(pResultInfo);
4,503,789✔
4771
  pInfo->result = 0;
4,503,338✔
4772
  pInfo->min = TSKEY_MAX;
4,503,338✔
4773
  pInfo->max = 0;
4,503,789✔
4774

4775
  if (pCtx->numOfParams > 1) {
4,503,789✔
4776
    pInfo->timeUnit = pCtx->param[1].param.i;
2,639,004✔
4777
  } else {
4778
    pInfo->timeUnit = 1;
1,862,851✔
4779
  }
4780

4781
  return TSDB_CODE_SUCCESS;
4,502,887✔
4782
}
4783

4784
int32_t elapsedFunction(SqlFunctionCtx* pCtx) {
5,169,184✔
4785
  int32_t numOfElems = 0;
5,169,184✔
4786

4787
  // Only the pre-computing information loaded and actual data does not loaded
4788
  SInputColumnInfoData* pInput = &pCtx->input;
5,169,184✔
4789
  SColumnDataAgg*       pAgg = pInput->pColumnDataAgg[0];
5,169,184✔
4790

4791
  SElapsedInfo* pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
5,168,798✔
4792

4793
  numOfElems = pInput->numOfRows;  // since this is the primary timestamp, no need to exclude NULL values
5,169,765✔
4794
  if (numOfElems == 0) {
5,165,576✔
4795
    // for stream
4796
    if (pCtx->end.key != INT64_MIN) {
×
4797
      pInfo->max = pCtx->end.key + 1;
×
4798
    }
4799
    goto _elapsed_over;
×
4800
  }
4801

4802
  if (pInput->colDataSMAIsSet) {
5,165,576✔
4803
    if (pInfo->min == TSKEY_MAX) {
×
4804
      pInfo->min = GET_INT64_VAL(&pAgg->min);
×
4805
      pInfo->max = GET_INT64_VAL(&pAgg->max);
×
4806
    } else {
4807
      if (pCtx->order == TSDB_ORDER_ASC) {
×
4808
        pInfo->max = GET_INT64_VAL(&pAgg->max);
×
4809
      } else {
4810
        pInfo->min = GET_INT64_VAL(&pAgg->min);
×
4811
      }
4812
    }
4813
  } else {  // computing based on the true data block
4814
    if (0 == pInput->numOfRows) {
5,170,216✔
4815
      if (pCtx->order == TSDB_ORDER_DESC) {
×
4816
        if (pCtx->end.key != INT64_MIN) {
×
4817
          pInfo->min = pCtx->end.key;
×
4818
        }
4819
      } else {
4820
        if (pCtx->end.key != INT64_MIN) {
×
4821
          pInfo->max = pCtx->end.key + 1;
×
4822
        }
4823
      }
4824
      goto _elapsed_over;
×
4825
    }
4826

4827
    SColumnInfoData* pCol = pInput->pData[0];
5,168,668✔
4828

4829
    int32_t start = pInput->startRowIndex;
5,168,217✔
4830
    TSKEY*  ptsList = (int64_t*)colDataGetData(pCol, 0);
5,168,733✔
4831
    if (pCtx->order == TSDB_ORDER_DESC) {
5,168,668✔
4832
      if (pCtx->start.key == INT64_MIN) {
33,674✔
4833
        pInfo->max = (pInfo->max < ptsList[start]) ? ptsList[start] : pInfo->max;
33,674✔
4834
      } else {
4835
        pInfo->max = pCtx->start.key + 1;
×
4836
      }
4837

4838
      if (pCtx->end.key == INT64_MIN) {
33,674✔
4839
        pInfo->min =
33,674✔
4840
            (pInfo->min > ptsList[start + pInput->numOfRows - 1]) ? ptsList[start + pInput->numOfRows - 1] : pInfo->min;
33,674✔
4841
      } else {
4842
        pInfo->min = pCtx->end.key;
×
4843
      }
4844
    } else {
4845
      if (pCtx->start.key == INT64_MIN) {
5,131,837✔
4846
        pInfo->min = (pInfo->min > ptsList[start]) ? ptsList[start] : pInfo->min;
5,135,059✔
4847
      } else {
4848
        pInfo->min = pCtx->start.key;
×
4849
      }
4850

4851
      if (pCtx->end.key == INT64_MIN) {
5,135,059✔
4852
        pInfo->max =
5,076,359✔
4853
            (pInfo->max < ptsList[start + pInput->numOfRows - 1]) ? ptsList[start + pInput->numOfRows - 1] : pInfo->max;
5,075,908✔
4854
      } else {
4855
        pInfo->max = pCtx->end.key + 1;
59,151✔
4856
      }
4857
    }
4858
  }
4859

4860
_elapsed_over:
5,167,831✔
4861
  // data in the check operation are all null, not output
4862
  SET_VAL(GET_RES_INFO(pCtx), numOfElems, 1);
5,167,831✔
4863

4864
  return TSDB_CODE_SUCCESS;
5,168,798✔
4865
}
4866

4867
static void elapsedTransferInfo(SElapsedInfo* pInput, SElapsedInfo* pOutput) {
×
4868
  pOutput->timeUnit = pInput->timeUnit;
×
4869
  if (pOutput->min > pInput->min) {
×
4870
    pOutput->min = pInput->min;
×
4871
  }
4872

4873
  if (pOutput->max < pInput->max) {
×
4874
    pOutput->max = pInput->max;
×
4875
  }
4876
}
×
4877

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

4885
  SElapsedInfo* pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
×
4886

4887
  int32_t start = pInput->startRowIndex;
×
4888

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

4895
  SET_VAL(GET_RES_INFO(pCtx), 1, 1);
×
4896
  return TSDB_CODE_SUCCESS;
×
4897
}
4898

4899
int32_t elapsedFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
4,503,789✔
4900
  SElapsedInfo* pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
4,503,789✔
4901
  double        result = (double)(pInfo->max - pInfo->min);
4,503,789✔
4902
  pInfo->result = fabs(result) / pInfo->timeUnit;
4,503,338✔
4903
  return functionFinalize(pCtx, pBlock);
4,503,338✔
4904
}
4905

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

4912
  if (NULL == res) {
×
4913
    return terrno;
×
4914
  }
4915
  (void)memcpy(varDataVal(res), pInfo, resultBytes);
×
4916
  varDataSetLen(res, resultBytes);
×
4917

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

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

4935
int32_t elapsedCombine(SqlFunctionCtx* pDestCtx, SqlFunctionCtx* pSourceCtx) {
×
4936
  SResultRowEntryInfo* pDResInfo = GET_RES_INFO(pDestCtx);
×
4937
  SElapsedInfo*        pDBuf = GET_ROWCELL_INTERBUF(pDResInfo);
×
4938

4939
  SResultRowEntryInfo* pSResInfo = GET_RES_INFO(pSourceCtx);
×
4940
  SElapsedInfo*        pSBuf = GET_ROWCELL_INTERBUF(pSResInfo);
×
4941

4942
  elapsedTransferInfo(pSBuf, pDBuf);
×
4943
  pDResInfo->numOfRes = TMAX(pDResInfo->numOfRes, pSResInfo->numOfRes);
×
4944
  pDResInfo->isNullRes &= pSResInfo->isNullRes;
×
4945
  return TSDB_CODE_SUCCESS;
×
4946
}
4947

4948
int32_t getHistogramInfoSize() {
725,044✔
4949
  return (int32_t)sizeof(SHistoFuncInfo) + HISTOGRAM_MAX_BINS_NUM * sizeof(SHistoFuncBin);
725,044✔
4950
}
4951

4952
bool getHistogramFuncEnv(SFunctionNode* UNUSED_PARAM(pFunc), SFuncExecEnv* pEnv) {
1,306,769✔
4953
  pEnv->calcMemSize = sizeof(SHistoFuncInfo) + HISTOGRAM_MAX_BINS_NUM * sizeof(SHistoFuncBin);
1,306,769✔
4954
  return true;
1,307,586✔
4955
}
4956

4957
static int8_t getHistogramBinType(char* binTypeStr) {
899,552✔
4958
  int8_t binType;
4959
  if (strcasecmp(binTypeStr, "user_input") == 0) {
899,552✔
4960
    binType = USER_INPUT_BIN;
446,887✔
4961
  } else if (strcasecmp(binTypeStr, "linear_bin") == 0) {
452,665✔
4962
    binType = LINEAR_BIN;
322,873✔
4963
  } else if (strcasecmp(binTypeStr, "log_bin") == 0) {
129,792✔
4964
    binType = LOG_BIN;
129,792✔
4965
  } else {
4966
    binType = UNKNOWN_BIN;
×
4967
  }
4968

4969
  return binType;
899,552✔
4970
}
4971

4972
static int32_t getHistogramBinDesc(SHistoFuncInfo* pInfo, char* binDescStr, int8_t binType, bool normalized) {
899,552✔
4973
  cJSON*  binDesc = cJSON_Parse(binDescStr);
899,552✔
4974
  int32_t numOfBins;
4975
  double* intervals;
4976
  if (cJSON_IsObject(binDesc)) { /* linaer/log bins */
899,552✔
4977
    int32_t numOfParams = cJSON_GetArraySize(binDesc);
452,665✔
4978
    int32_t startIndex;
4979
    if (numOfParams != 4) {
452,665✔
4980
      cJSON_Delete(binDesc);
×
4981
      return TSDB_CODE_FAILED;
×
4982
    }
4983

4984
    cJSON* start = cJSON_GetObjectItem(binDesc, "start");
452,665✔
4985
    cJSON* factor = cJSON_GetObjectItem(binDesc, "factor");
452,665✔
4986
    cJSON* width = cJSON_GetObjectItem(binDesc, "width");
452,292✔
4987
    cJSON* count = cJSON_GetObjectItem(binDesc, "count");
451,928✔
4988
    cJSON* infinity = cJSON_GetObjectItem(binDesc, "infinity");
452,665✔
4989

4990
    if (!cJSON_IsNumber(start) || !cJSON_IsNumber(count) || !cJSON_IsBool(infinity)) {
452,665✔
4991
      cJSON_Delete(binDesc);
×
4992
      return TSDB_CODE_FAILED;
×
4993
    }
4994

4995
    if (count->valueint <= 0 || count->valueint > 1000) {  // limit count to 1000
452,665✔
4996
      cJSON_Delete(binDesc);
×
4997
      return TSDB_CODE_FAILED;
×
4998
    }
4999

5000
    if (isinf(start->valuedouble) || (width != NULL && isinf(width->valuedouble)) ||
452,665✔
5001
        (factor != NULL && isinf(factor->valuedouble)) || (count != NULL && isinf(count->valuedouble))) {
452,301✔
5002
      cJSON_Delete(binDesc);
×
5003
      return TSDB_CODE_FAILED;
×
5004
    }
5005

5006
    int32_t counter = (int32_t)count->valueint;
452,665✔
5007
    if (infinity->valueint == false) {
452,665✔
5008
      startIndex = 0;
411,644✔
5009
      numOfBins = counter + 1;
411,644✔
5010
    } else {
5011
      startIndex = 1;
40,284✔
5012
      numOfBins = counter + 3;
40,284✔
5013
    }
5014

5015
    intervals = taosMemoryCalloc(numOfBins, sizeof(double));
451,928✔
5016
    if (NULL == intervals) {
452,292✔
5017
      cJSON_Delete(binDesc);
×
5018
      qError("histogram function out of memory");
×
5019
      return terrno;
×
5020
    }
5021
    if (cJSON_IsNumber(width) && factor == NULL && binType == LINEAR_BIN) {
452,292✔
5022
      // linear bin process
5023
      if (width->valuedouble == 0) {
322,500✔
5024
        taosMemoryFree(intervals);
×
5025
        cJSON_Delete(binDesc);
×
5026
        return TSDB_CODE_FAILED;
×
5027
      }
5028
      for (int i = 0; i < counter + 1; ++i) {
1,958,965✔
5029
        intervals[startIndex] = start->valuedouble + i * width->valuedouble;
1,635,355✔
5030
        if (isinf(intervals[startIndex])) {
1,635,346✔
5031
          taosMemoryFree(intervals);
×
5032
          cJSON_Delete(binDesc);
×
5033
          return TSDB_CODE_FAILED;
×
5034
        }
5035
        startIndex++;
1,636,092✔
5036
      }
5037
    } else if (cJSON_IsNumber(factor) && width == NULL && binType == LOG_BIN) {
129,792✔
5038
      // log bin process
5039
      if (start->valuedouble == 0) {
129,792✔
5040
        taosMemoryFree(intervals);
×
5041
        cJSON_Delete(binDesc);
×
5042
        return TSDB_CODE_FAILED;
×
5043
      }
5044
      if (factor->valuedouble < 0 || factor->valuedouble == 0 || factor->valuedouble == 1) {
129,792✔
5045
        taosMemoryFree(intervals);
×
5046
        cJSON_Delete(binDesc);
×
5047
        return TSDB_CODE_FAILED;
×
5048
      }
5049
      for (int i = 0; i < counter + 1; ++i) {
609,600✔
5050
        intervals[startIndex] = start->valuedouble * pow(factor->valuedouble, i * 1.0);
479,808✔
5051
        if (isinf(intervals[startIndex])) {
479,808✔
5052
          taosMemoryFree(intervals);
×
5053
          cJSON_Delete(binDesc);
×
5054
          return TSDB_CODE_FAILED;
×
5055
        }
5056
        startIndex++;
479,808✔
5057
      }
5058
    } else {
5059
      taosMemoryFree(intervals);
×
5060
      cJSON_Delete(binDesc);
×
5061
      return TSDB_CODE_FAILED;
×
5062
    }
5063

5064
    if (infinity->valueint == true) {
453,402✔
5065
      intervals[0] = -INFINITY;
40,657✔
5066
      intervals[numOfBins - 1] = INFINITY;
40,657✔
5067
      // in case of desc bin orders, -inf/inf should be swapped
5068
      if (numOfBins < 4) {
40,284✔
5069
        return TSDB_CODE_FAILED;
×
5070
      }
5071
      if (intervals[1] > intervals[numOfBins - 2]) {
40,284✔
UNCOV
5072
        TSWAP(intervals[0], intervals[numOfBins - 1]);
×
5073
      }
5074
    }
5075
  } else if (cJSON_IsArray(binDesc)) { /* user input bins */
446,887✔
5076
    if (binType != USER_INPUT_BIN) {
446,887✔
5077
      cJSON_Delete(binDesc);
×
5078
      return TSDB_CODE_FAILED;
×
5079
    }
5080
    numOfBins = cJSON_GetArraySize(binDesc);
446,887✔
5081
    intervals = taosMemoryCalloc(numOfBins, sizeof(double));
446,887✔
5082
    if (NULL == intervals) {
446,887✔
5083
      cJSON_Delete(binDesc);
×
5084
      qError("histogram function out of memory");
×
5085
      return terrno;
×
5086
    }
5087
    cJSON* bin = binDesc->child;
446,887✔
5088
    if (bin == NULL) {
446,887✔
5089
      taosMemoryFree(intervals);
×
5090
      cJSON_Delete(binDesc);
×
5091
      return TSDB_CODE_FAILED;
×
5092
    }
5093
    int i = 0;
446,887✔
5094
    while (bin) {
1,934,891✔
5095
      intervals[i] = bin->valuedouble;
1,488,004✔
5096
      if (!cJSON_IsNumber(bin)) {
1,488,004✔
5097
        taosMemoryFree(intervals);
×
5098
        cJSON_Delete(binDesc);
×
5099
        return TSDB_CODE_FAILED;
×
5100
      }
5101
      if (i != 0 && intervals[i] <= intervals[i - 1]) {
1,488,004✔
5102
        taosMemoryFree(intervals);
×
5103
        cJSON_Delete(binDesc);
×
5104
        return TSDB_CODE_FAILED;
×
5105
      }
5106
      bin = bin->next;
1,488,004✔
5107
      i++;
1,488,004✔
5108
    }
5109
  } else {
5110
    cJSON_Delete(binDesc);
×
5111
    return TSDB_CODE_FAILED;
×
5112
  }
5113

5114
  pInfo->numOfBins = numOfBins - 1;
899,179✔
5115
  pInfo->normalized = normalized;
899,552✔
5116
  for (int32_t i = 0; i < pInfo->numOfBins; ++i) {
3,685,218✔
5117
    pInfo->bins[i].lower = intervals[i] < intervals[i + 1] ? intervals[i] : intervals[i + 1];
2,786,403✔
5118
    pInfo->bins[i].upper = intervals[i + 1] > intervals[i] ? intervals[i + 1] : intervals[i];
2,786,030✔
5119
    pInfo->bins[i].count = 0;
2,785,657✔
5120
  }
5121

5122
  taosMemoryFree(intervals);
898,815✔
5123
  cJSON_Delete(binDesc);
899,179✔
5124

5125
  return TSDB_CODE_SUCCESS;
899,552✔
5126
}
5127

5128
int32_t histogramFunctionSetup(SqlFunctionCtx* pCtx, SResultRowEntryInfo* pResultInfo) {
899,552✔
5129
  if (pResultInfo->initialized) {
899,552✔
5130
    return TSDB_CODE_SUCCESS;
×
5131
  }
5132
  if (TSDB_CODE_SUCCESS != functionSetup(pCtx, pResultInfo)) {
899,552✔
5133
    return TSDB_CODE_FUNC_SETUP_ERROR;
×
5134
  }
5135

5136
  SHistoFuncInfo* pInfo = GET_ROWCELL_INTERBUF(pResultInfo);
899,552✔
5137
  pInfo->numOfBins = 0;
899,552✔
5138
  pInfo->totalCount = 0;
899,552✔
5139
  pInfo->normalized = 0;
899,552✔
5140

5141
  char* binTypeStr = taosStrndup(varDataVal(pCtx->param[1].param.pz), varDataLen(pCtx->param[1].param.pz));
899,552✔
5142
  if (binTypeStr == NULL) {
899,552✔
5143
    return terrno;
×
5144
  }
5145
  int8_t binType = getHistogramBinType(binTypeStr);
899,552✔
5146
  taosMemoryFree(binTypeStr);
899,552✔
5147

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

5167
  return TSDB_CODE_SUCCESS;
899,552✔
5168
}
5169

5170
static int32_t histogramFunctionImpl(SqlFunctionCtx* pCtx, bool isPartial) {
1,048,822✔
5171
  SHistoFuncInfo* pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
1,048,822✔
5172

5173
  SInputColumnInfoData* pInput = &pCtx->input;
1,048,085✔
5174
  SColumnInfoData*      pCol = pInput->pData[0];
1,048,822✔
5175

5176
  int32_t type = pInput->pData[0]->info.type;
1,048,822✔
5177

5178
  int32_t start = pInput->startRowIndex;
1,048,306✔
5179
  int32_t numOfRows = pInput->numOfRows;
1,048,822✔
5180

5181
  int32_t numOfElems = 0;
1,108,900✔
5182
  for (int32_t i = start; i < numOfRows + start; ++i) {
151,463,761✔
5183
    if (pCol->hasNull && colDataIsNull_f(pCol, i)) {
150,415,455✔
5184
      continue;
72,072,101✔
5185
    }
5186

5187
    numOfElems++;
78,340,290✔
5188

5189
    char*  data = colDataGetData(pCol, i);
78,340,290✔
5190
    double v;
5191
    GET_TYPED_DATA(v, double, type, data, typeGetTypeModFromColInfo(&pCol->info));
78,371,976✔
5192

5193
    for (int32_t k = 0; k < pInfo->numOfBins; ++k) {
265,727,450✔
5194
      if (v > pInfo->bins[k].lower && v <= pInfo->bins[k].upper) {
214,973,947✔
5195
        pInfo->bins[k].count++;
27,561,335✔
5196
        pInfo->totalCount++;
27,567,303✔
5197
        break;
27,566,930✔
5198
      }
5199
    }
5200
  }
5201

5202
  if (!isPartial) {
1,048,306✔
5203
    GET_RES_INFO(pCtx)->numOfRes = pInfo->numOfBins;
709,724✔
5204
  } else {
5205
    GET_RES_INFO(pCtx)->numOfRes = 1;
338,582✔
5206
  }
5207
  return TSDB_CODE_SUCCESS;
1,048,822✔
5208
}
5209

5210
int32_t histogramFunction(SqlFunctionCtx* pCtx) { return histogramFunctionImpl(pCtx, false); }
710,240✔
5211

5212
int32_t histogramFunctionPartial(SqlFunctionCtx* pCtx) { return histogramFunctionImpl(pCtx, true); }
338,582✔
5213

5214
static void histogramTransferInfo(SHistoFuncInfo* pInput, SHistoFuncInfo* pOutput) {
216,302✔
5215
  pOutput->normalized = pInput->normalized;
216,302✔
5216
  pOutput->numOfBins = pInput->numOfBins;
216,302✔
5217
  pOutput->totalCount += pInput->totalCount;
216,302✔
5218
  for (int32_t k = 0; k < pOutput->numOfBins; ++k) {
1,139,720✔
5219
    pOutput->bins[k].lower = pInput->bins[k].lower;
923,418✔
5220
    pOutput->bins[k].upper = pInput->bins[k].upper;
923,418✔
5221
    pOutput->bins[k].count += pInput->bins[k].count;
923,418✔
5222
  }
5223
}
216,302✔
5224

5225
int32_t histogramFunctionMerge(SqlFunctionCtx* pCtx) {
216,302✔
5226
  SInputColumnInfoData* pInput = &pCtx->input;
216,302✔
5227
  SColumnInfoData*      pCol = pInput->pData[0];
216,302✔
5228
  if (pCol->info.type != TSDB_DATA_TYPE_BINARY) {
216,302✔
5229
    return TSDB_CODE_FUNC_FUNTION_PARA_TYPE;
×
5230
  }
5231

5232
  SHistoFuncInfo* pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
216,302✔
5233

5234
  int32_t start = pInput->startRowIndex;
216,302✔
5235

5236
  for (int32_t i = start; i < start + pInput->numOfRows; ++i) {
432,604✔
5237
    char*           data = colDataGetData(pCol, i);
216,302✔
5238
    SHistoFuncInfo* pInputInfo = (SHistoFuncInfo*)varDataVal(data);
216,302✔
5239
    histogramTransferInfo(pInputInfo, pInfo);
216,302✔
5240
  }
5241

5242
  SET_VAL(GET_RES_INFO(pCtx), pInfo->numOfBins, pInfo->numOfBins);
216,302✔
5243
  return TSDB_CODE_SUCCESS;
216,302✔
5244
}
5245

5246
int32_t histogramFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
878,246✔
5247
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
878,246✔
5248
  SHistoFuncInfo*      pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
878,246✔
5249
  int32_t              slotId = pCtx->pExpr->base.resSchema.slotId;
878,246✔
5250
  SColumnInfoData*     pCol = taosArrayGet(pBlock->pDataBlock, slotId);
877,750✔
5251
  int32_t              code = TSDB_CODE_SUCCESS;
878,246✔
5252

5253
  int32_t currentRow = pBlock->info.rows;
878,246✔
5254
  if (NULL == pCol) {
878,246✔
5255
    return TSDB_CODE_OUT_OF_RANGE;
×
5256
  }
5257

5258
  if (pInfo->normalized) {
878,246✔
5259
    for (int32_t k = 0; k < pResInfo->numOfRes; ++k) {
744,476✔
5260
      if (pInfo->totalCount != 0) {
467,581✔
5261
        pInfo->bins[k].percentage = pInfo->bins[k].count / (double)pInfo->totalCount;
66,189✔
5262
      } else {
5263
        pInfo->bins[k].percentage = 0;
401,392✔
5264
      }
5265
    }
5266
  }
5267

5268
  for (int32_t i = 0; i < pResInfo->numOfRes; ++i) {
3,542,534✔
5269
    int32_t len;
5270
    char    buf[512] = {0};
2,664,288✔
5271
    if (!pInfo->normalized) {
2,663,792✔
5272
      len = tsnprintf(varDataVal(buf), sizeof(buf) - VARSTR_HEADER_SIZE,
2,196,211✔
5273
                      "{\"lower_bin\":%g, \"upper_bin\":%g, \"count\":%" PRId64 "}", pInfo->bins[i].lower,
5274
                      pInfo->bins[i].upper, pInfo->bins[i].count);
5275
    } else {
5276
      len = tsnprintf(varDataVal(buf), sizeof(buf) - VARSTR_HEADER_SIZE,
468,573✔
5277
                      "{\"lower_bin\":%g, \"upper_bin\":%g, \"count\":%lf}", pInfo->bins[i].lower, pInfo->bins[i].upper,
5278
                      pInfo->bins[i].percentage);
5279
    }
5280
    varDataSetLen(buf, len);
2,664,288✔
5281
    code = colDataSetVal(pCol, currentRow, buf, false);
2,664,288✔
5282
    if (TSDB_CODE_SUCCESS != code) {
2,664,288✔
5283
      return code;
×
5284
    }
5285
    currentRow++;
2,664,288✔
5286
  }
5287

5288
  return code;
878,246✔
5289
}
5290

5291
int32_t histogramPartialFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
216,302✔
5292
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
216,302✔
5293
  SHistoFuncInfo*      pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
216,302✔
5294
  int32_t              resultBytes = getHistogramInfoSize();
216,302✔
5295
  char*                res = taosMemoryCalloc(resultBytes + VARSTR_HEADER_SIZE, sizeof(char));
216,302✔
5296

5297
  if (NULL == res) {
216,302✔
5298
    return terrno;
×
5299
  }
5300
  (void)memcpy(varDataVal(res), pInfo, resultBytes);
216,302✔
5301
  varDataSetLen(res, resultBytes);
216,302✔
5302

5303
  int32_t          slotId = pCtx->pExpr->base.resSchema.slotId;
216,302✔
5304
  int32_t          code = TSDB_CODE_SUCCESS;
216,302✔
5305
  SColumnInfoData* pCol = taosArrayGet(pBlock->pDataBlock, slotId);
216,302✔
5306
  if (NULL == pCol) {
216,302✔
5307
    code = terrno;
×
5308
    goto _exit;
×
5309
  }
5310
  code = colDataSetVal(pCol, pBlock->info.rows, res, false);
216,302✔
5311

5312
_exit:
216,302✔
5313
  taosMemoryFree(res);
216,302✔
5314
  return code;
216,302✔
5315
}
5316

5317
int32_t histogramCombine(SqlFunctionCtx* pDestCtx, SqlFunctionCtx* pSourceCtx) {
×
5318
  SResultRowEntryInfo* pDResInfo = GET_RES_INFO(pDestCtx);
×
5319
  SHistoFuncInfo*      pDBuf = GET_ROWCELL_INTERBUF(pDResInfo);
×
5320

5321
  SResultRowEntryInfo* pSResInfo = GET_RES_INFO(pSourceCtx);
×
5322
  SHistoFuncInfo*      pSBuf = GET_ROWCELL_INTERBUF(pSResInfo);
×
5323

5324
  histogramTransferInfo(pSBuf, pDBuf);
×
5325
  pDResInfo->numOfRes = TMAX(pDResInfo->numOfRes, pSResInfo->numOfRes);
×
5326
  pDResInfo->isNullRes &= pSResInfo->isNullRes;
×
5327
  return TSDB_CODE_SUCCESS;
×
5328
}
5329

5330
int32_t getHLLInfoSize() { return (int32_t)sizeof(SHLLInfo); }
252,816✔
5331

5332
bool getHLLFuncEnv(SFunctionNode* UNUSED_PARAM(pFunc), SFuncExecEnv* pEnv) {
3,705,723✔
5333
  pEnv->calcMemSize = sizeof(SHLLInfo);
3,705,723✔
5334
  return true;
3,706,233✔
5335
}
5336

5337
static uint8_t hllCountNum(void* data, int32_t bytes, int32_t* buk) {
537,123,763✔
5338
  uint64_t hash = MurmurHash3_64(data, bytes);
537,123,763✔
5339
  int32_t  index = hash & HLL_BUCKET_MASK;
537,052,889✔
5340
  hash >>= HLL_BUCKET_BITS;
537,052,889✔
5341
  hash |= ((uint64_t)1 << HLL_DATA_BITS);
537,052,889✔
5342
  uint64_t bit = 1;
537,052,889✔
5343
  uint8_t  count = 1;
537,052,889✔
5344
  while ((hash & bit) == 0) {
1,101,867,076✔
5345
    count++;
564,814,187✔
5346
    bit <<= 1;
564,814,187✔
5347
  }
5348
  *buk = index;
537,052,889✔
5349
  return count;
537,085,934✔
5350
}
5351

5352
static void hllBucketHisto(uint8_t* buckets, int32_t* bucketHisto) {
8,823,296✔
5353
  uint64_t* word = (uint64_t*)buckets;
8,823,296✔
5354
  uint8_t*  bytes;
5355

5356
  for (int32_t j = 0; j < HLL_BUCKETS >> 3; j++) {
2,147,483,647✔
5357
    if (*word == 0) {
2,147,483,647✔
5358
      bucketHisto[0] += 8;
2,147,483,647✔
5359
    } else {
5360
      bytes = (uint8_t*)word;
23,038,622✔
5361
      bucketHisto[bytes[0]]++;
23,038,622✔
5362
      bucketHisto[bytes[1]]++;
45,283,760✔
5363
      bucketHisto[bytes[2]]++;
45,283,760✔
5364
      bucketHisto[bytes[3]]++;
45,283,760✔
5365
      bucketHisto[bytes[4]]++;
45,283,760✔
5366
      bucketHisto[bytes[5]]++;
45,283,760✔
5367
      bucketHisto[bytes[6]]++;
45,283,760✔
5368
      bucketHisto[bytes[7]]++;
45,283,760✔
5369
    }
5370
    word++;
2,147,483,647✔
5371
  }
5372
}
4,858,430✔
5373
static double hllTau(double x) {
8,823,296✔
5374
  if (x == 0. || x == 1.) return 0.;
8,823,296✔
5375
  double zPrime;
5376
  double y = 1.0;
×
5377
  double z = 1 - x;
×
5378
  do {
5379
    x = sqrt(x);
×
5380
    zPrime = z;
×
5381
    y *= 0.5;
×
5382
    z -= pow(1 - x, 2) * y;
×
5383
  } while (zPrime != z);
×
5384
  return z / 3;
×
5385
}
5386

5387
static double hllSigma(double x) {
8,823,296✔
5388
  if (x == 1.0) return INFINITY;
8,823,296✔
5389
  double zPrime;
5390
  double y = 1;
6,027,406✔
5391
  double z = x;
6,027,406✔
5392
  do {
5393
    x *= x;
118,761,149✔
5394
    zPrime = z;
118,761,149✔
5395
    z += x * y;
118,761,149✔
5396
    y += y;
118,761,149✔
5397
  } while (zPrime != z);
118,761,149✔
5398
  return z;
6,027,406✔
5399
}
5400

5401
// estimate the cardinality, the algorithm refer this paper: "New cardinality estimation algorithms for HyperLogLog
5402
// sketches"
5403
static uint64_t hllCountCnt(uint8_t* buckets) {
8,823,296✔
5404
  double  m = HLL_BUCKETS;
8,823,296✔
5405
  int32_t buckethisto[64] = {0};
8,823,296✔
5406
  hllBucketHisto(buckets, buckethisto);
8,822,780✔
5407

5408
  double z = m * hllTau((m - buckethisto[HLL_DATA_BITS + 1]) / (double)m);
8,823,296✔
5409
  for (int j = HLL_DATA_BITS; j >= 1; --j) {
449,970,036✔
5410
    z += buckethisto[j];
441,146,740✔
5411
    z *= 0.5;
441,146,740✔
5412
  }
5413

5414
  z += m * hllSigma(buckethisto[0] / (double)m);
8,823,296✔
5415
  double E = (double)llroundl(HLL_ALPHA_INF * m * m / z);
8,823,296✔
5416

5417
  return (uint64_t)E;
8,823,296✔
5418
}
5419

5420
int32_t hllFunction(SqlFunctionCtx* pCtx) {
9,064,626✔
5421
  SHLLInfo* pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
9,064,626✔
5422

5423
  SInputColumnInfoData* pInput = &pCtx->input;
9,067,273✔
5424
  SColumnInfoData*      pCol = pInput->pData[0];
9,066,278✔
5425

5426
  int32_t type = pCol->info.type;
9,063,264✔
5427
  int32_t bytes = pCol->info.bytes;
9,065,658✔
5428

5429
  int32_t start = pInput->startRowIndex;
9,064,688✔
5430
  int32_t numOfRows = pInput->numOfRows;
9,065,720✔
5431

5432
  int32_t numOfElems = 0;
9,065,658✔
5433
  if (IS_NULL_TYPE(type)) {
9,065,658✔
5434
    goto _hll_over;
133,935✔
5435
  }
5436

5437
  for (int32_t i = start; i < numOfRows + start; ++i) {
699,260,420✔
5438
    if (pCol->hasNull && colDataIsNull_s(pCol, i)) {
852,637,299✔
5439
      continue;
153,229,398✔
5440
    }
5441

5442
    numOfElems++;
537,081,488✔
5443

5444
    char* data = colDataGetData(pCol, i);
537,081,488✔
5445
    if (IS_VAR_DATA_TYPE(type)) {
537,129,051✔
5446
      if (IS_STR_DATA_BLOB(type)) {
96,520,870✔
5447
        bytes = blobDataLen(data);
49✔
5448
        data = blobDataVal(data);
×
5449
      } else {
5450
        bytes = varDataLen(data);
96,521,865✔
5451
        data = varDataVal(data);
96,521,865✔
5452
      }
5453
    }
5454

5455
    int32_t index = 0;
537,130,562✔
5456
    uint8_t count = hllCountNum(data, bytes, &index);
537,125,311✔
5457
    uint8_t oldcount = pInfo->buckets[index];
537,095,243✔
5458
    if (count > oldcount) {
537,105,790✔
5459
      pInfo->buckets[index] = count;
85,524,869✔
5460
    }
5461
  }
5462

5463
_hll_over:
8,936,491✔
5464
  pInfo->totalCount += numOfElems;
9,070,426✔
5465

5466
  if (pInfo->totalCount == 0 && !tsCountAlwaysReturnValue) {
9,067,838✔
5467
    SET_VAL(GET_RES_INFO(pCtx), 0, 1);
238,662✔
5468
  } else {
5469
    SET_VAL(GET_RES_INFO(pCtx), 1, 1);
8,828,138✔
5470
  }
5471

5472
  return TSDB_CODE_SUCCESS;
9,067,844✔
5473
}
5474

5475
static void hllTransferInfo(SHLLInfo* pInput, SHLLInfo* pOutput) {
252,816✔
5476
  for (int32_t k = 0; k < HLL_BUCKETS; ++k) {
2,147,483,647✔
5477
    if (pOutput->buckets[k] < pInput->buckets[k]) {
2,147,483,647✔
5478
      pOutput->buckets[k] = pInput->buckets[k];
30,395,380✔
5479
    }
5480
  }
5481
  pOutput->totalCount += pInput->totalCount;
197,927✔
5482
}
252,816✔
5483

5484
int32_t hllFunctionMerge(SqlFunctionCtx* pCtx) {
252,816✔
5485
  SInputColumnInfoData* pInput = &pCtx->input;
252,816✔
5486
  SColumnInfoData*      pCol = pInput->pData[0];
252,816✔
5487

5488
  if (IS_NULL_TYPE(pCol->info.type)) {
252,816✔
5489
    SET_VAL(GET_RES_INFO(pCtx), 0, 1);
×
5490
    return TSDB_CODE_SUCCESS;
×
5491
  }
5492

5493
  if (pCol->info.type != TSDB_DATA_TYPE_BINARY) {
252,816✔
5494
    return TSDB_CODE_SUCCESS;
×
5495
  }
5496

5497
  SHLLInfo* pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
252,816✔
5498

5499
  int32_t start = pInput->startRowIndex;
252,816✔
5500

5501
  for (int32_t i = start; i < start + pInput->numOfRows; ++i) {
505,632✔
5502
    if (colDataIsNull_s(pCol, i)) continue;
505,632✔
5503
    char*     data = colDataGetData(pCol, i);
252,816✔
5504
    SHLLInfo* pInputInfo = (SHLLInfo*)varDataVal(data);
252,816✔
5505
    hllTransferInfo(pInputInfo, pInfo);
252,816✔
5506
  }
5507

5508
  if (pInfo->totalCount == 0 && !tsCountAlwaysReturnValue) {
252,816✔
5509
    SET_VAL(GET_RES_INFO(pCtx), 0, 1);
70✔
5510
  } else {
5511
    SET_VAL(GET_RES_INFO(pCtx), 1, 1);
252,746✔
5512
  }
5513

5514
  return TSDB_CODE_SUCCESS;
252,816✔
5515
}
5516

5517
int32_t hllFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
8,823,296✔
5518
  SResultRowEntryInfo* pInfo = GET_RES_INFO(pCtx);
8,823,296✔
5519

5520
  SHLLInfo* pHllInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
8,823,296✔
5521
  pHllInfo->result = hllCountCnt(pHllInfo->buckets);
8,823,296✔
5522
  if (tsCountAlwaysReturnValue && pHllInfo->result == 0) {
8,823,296✔
5523
    pInfo->numOfRes = 1;
2,557,718✔
5524
  }
5525

5526
  return functionFinalize(pCtx, pBlock);
8,823,296✔
5527
}
5528

5529
int32_t hllPartialFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
252,816✔
5530
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
252,816✔
5531
  SHLLInfo*            pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
252,816✔
5532
  int32_t              resultBytes = getHLLInfoSize();
252,816✔
5533
  char*                res = taosMemoryCalloc(resultBytes + VARSTR_HEADER_SIZE, sizeof(char));
252,816✔
5534

5535
  if (NULL == res) {
252,816✔
5536
    return terrno;
×
5537
  }
5538
  (void)memcpy(varDataVal(res), pInfo, resultBytes);
252,816✔
5539
  varDataSetLen(res, resultBytes);
252,816✔
5540

5541
  int32_t          slotId = pCtx->pExpr->base.resSchema.slotId;
252,816✔
5542
  int32_t          code = TSDB_CODE_SUCCESS;
252,816✔
5543
  SColumnInfoData* pCol = taosArrayGet(pBlock->pDataBlock, slotId);
252,816✔
5544
  if (NULL == pCol) {
252,816✔
5545
    code = terrno;
×
5546
    goto _exit;
×
5547
  }
5548

5549
  code = colDataSetVal(pCol, pBlock->info.rows, res, false);
252,816✔
5550

5551
_exit:
252,816✔
5552
  taosMemoryFree(res);
252,816✔
5553
  return code;
252,816✔
5554
}
5555

5556
int32_t hllCombine(SqlFunctionCtx* pDestCtx, SqlFunctionCtx* pSourceCtx) {
×
5557
  SResultRowEntryInfo* pDResInfo = GET_RES_INFO(pDestCtx);
×
5558
  SHLLInfo*            pDBuf = GET_ROWCELL_INTERBUF(pDResInfo);
×
5559

5560
  SResultRowEntryInfo* pSResInfo = GET_RES_INFO(pSourceCtx);
×
5561
  SHLLInfo*            pSBuf = GET_ROWCELL_INTERBUF(pSResInfo);
×
5562

5563
  hllTransferInfo(pSBuf, pDBuf);
×
5564
  pDResInfo->numOfRes = TMAX(pDResInfo->numOfRes, pSResInfo->numOfRes);
×
5565
  pDResInfo->isNullRes &= pSResInfo->isNullRes;
×
5566
  return TSDB_CODE_SUCCESS;
×
5567
}
5568

5569
bool getStateFuncEnv(SFunctionNode* UNUSED_PARAM(pFunc), SFuncExecEnv* pEnv) {
1,291,420✔
5570
  pEnv->calcMemSize = sizeof(SStateInfo);
1,291,420✔
5571
  return true;
1,291,784✔
5572
}
5573

5574
static int8_t getStateOpType(char* opStr) {
1,314,962✔
5575
  int8_t opType;
5576
  if (strncasecmp(opStr, "LT", 2) == 0) {
1,314,962✔
5577
    opType = STATE_OPER_LT;
601,244✔
5578
  } else if (strncasecmp(opStr, "GT", 2) == 0) {
713,718✔
5579
    opType = STATE_OPER_GT;
237,394✔
5580
  } else if (strncasecmp(opStr, "LE", 2) == 0) {
476,324✔
5581
    opType = STATE_OPER_LE;
110,486✔
5582
  } else if (strncasecmp(opStr, "GE", 2) == 0) {
365,838✔
5583
    opType = STATE_OPER_GE;
108,626✔
5584
  } else if (strncasecmp(opStr, "NE", 2) == 0) {
257,212✔
5585
    opType = STATE_OPER_NE;
106,848✔
5586
  } else if (strncasecmp(opStr, "EQ", 2) == 0) {
150,364✔
5587
    opType = STATE_OPER_EQ;
150,000✔
5588
  } else {
5589
    opType = STATE_OPER_INVALID;
364✔
5590
  }
5591

5592
  return opType;
1,314,962✔
5593
}
5594

5595
static bool checkStateOp(int8_t op, SColumnInfoData* pCol, int32_t index, SVariant param) {
71,442,738✔
5596
  char* data = colDataGetData(pCol, index);
71,442,738✔
5597
  switch (pCol->info.type) {
71,442,738✔
5598
    case TSDB_DATA_TYPE_TINYINT: {
15,605,064✔
5599
      int8_t v = *(int8_t*)data;
15,605,064✔
5600
      STATE_COMP(op, v, param);
15,605,064✔
5601
      break;
×
5602
    }
5603
    case TSDB_DATA_TYPE_UTINYINT: {
29,707,104✔
5604
      uint8_t v = *(uint8_t*)data;
29,707,104✔
5605
      STATE_COMP(op, v, param);
29,707,104✔
5606
      break;
×
5607
    }
5608
    case TSDB_DATA_TYPE_SMALLINT: {
667,728✔
5609
      int16_t v = *(int16_t*)data;
667,728✔
5610
      STATE_COMP(op, v, param);
667,728✔
5611
      break;
×
5612
    }
5613
    case TSDB_DATA_TYPE_USMALLINT: {
609,120✔
5614
      uint16_t v = *(uint16_t*)data;
609,120✔
5615
      STATE_COMP(op, v, param);
609,120✔
5616
      break;
×
5617
    }
5618
    case TSDB_DATA_TYPE_INT: {
21,353,631✔
5619
      int32_t v = *(int32_t*)data;
21,353,631✔
5620
      STATE_COMP(op, v, param);
21,353,631✔
5621
      break;
×
5622
    }
5623
    case TSDB_DATA_TYPE_UINT: {
609,120✔
5624
      uint32_t v = *(uint32_t*)data;
609,120✔
5625
      STATE_COMP(op, v, param);
609,120✔
5626
      break;
×
5627
    }
5628
    case TSDB_DATA_TYPE_BIGINT: {
677,052✔
5629
      int64_t v = *(int64_t*)data;
677,052✔
5630
      STATE_COMP(op, v, param);
677,052✔
5631
      break;
×
5632
    }
5633
    case TSDB_DATA_TYPE_UBIGINT: {
609,120✔
5634
      uint64_t v = *(uint64_t*)data;
609,120✔
5635
      STATE_COMP(op, v, param);
609,120✔
5636
      break;
×
5637
    }
5638
    case TSDB_DATA_TYPE_FLOAT: {
667,728✔
5639
      float v = *(float*)data;
667,728✔
5640
      STATE_COMP(op, v, param);
667,728✔
5641
      break;
×
5642
    }
5643
    case TSDB_DATA_TYPE_DOUBLE: {
937,071✔
5644
      double v = *(double*)data;
937,071✔
5645
      STATE_COMP(op, v, param);
937,071✔
5646
      break;
×
5647
    }
5648
    default: {
×
5649
      return false;
×
5650
    }
5651
  }
5652
  return false;
×
5653
}
5654

5655
int32_t stateCountFunction(SqlFunctionCtx* pCtx) {
379,876✔
5656
  int32_t              code = TSDB_CODE_SUCCESS;
379,876✔
5657
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
379,876✔
5658
  SStateInfo*          pInfo = GET_ROWCELL_INTERBUF(pResInfo);
379,876✔
5659

5660
  SInputColumnInfoData* pInput = &pCtx->input;
379,876✔
5661
  TSKEY*                tsList = (int64_t*)pInput->pPTS->pData;
379,876✔
5662

5663
  SColumnInfoData* pInputCol = pInput->pData[0];
379,876✔
5664

5665
  int32_t          numOfElems = 0;
379,876✔
5666
  SColumnInfoData* pOutput = (SColumnInfoData*)pCtx->pOutput;
379,876✔
5667

5668
  int8_t op = getStateOpType(varDataVal(pCtx->param[1].param.pz));
379,876✔
5669
  if (STATE_OPER_INVALID == op) {
379,876✔
5670
    return 0;
×
5671
  }
5672

5673
  for (int32_t i = pInput->startRowIndex; i < pInput->numOfRows + pInput->startRowIndex; i += 1) {
83,658,153✔
5674
    if (pInfo->isPrevTsSet == true && tsList[i] == pInfo->prevTs) {
83,279,105✔
5675
      return TSDB_CODE_FUNC_DUP_TIMESTAMP;
828✔
5676
    } else {
5677
      pInfo->prevTs = tsList[i];
83,278,277✔
5678
    }
5679

5680
    pInfo->isPrevTsSet = true;
83,278,277✔
5681
    numOfElems++;
83,278,277✔
5682

5683
    if (colDataIsNull_f(pInputCol, i)) {
83,278,277✔
5684
      colDataSetNULL(pOutput, i);
57,185,324✔
5685
      // handle selectivity
5686
      if (pCtx->subsidiaries.num > 0) {
57,185,324✔
5687
        code = appendSelectivityValue(pCtx, i, pCtx->offset + numOfElems - 1);
3,861✔
5688
        if (TSDB_CODE_SUCCESS != code) {
3,861✔
5689
          return code;
×
5690
        }
5691
      }
5692
      continue;
57,185,324✔
5693
    }
5694

5695
    bool ret = checkStateOp(op, pInputCol, i, pCtx->param[2].param);
26,092,953✔
5696

5697
    int64_t output = -1;
26,092,953✔
5698
    if (ret) {
26,092,953✔
5699
      output = ++pInfo->count;
14,069,882✔
5700
    } else {
5701
      pInfo->count = 0;
12,023,071✔
5702
    }
5703
    code = colDataSetVal(pOutput, pCtx->offset + numOfElems - 1, (char*)&output, false);
26,092,953✔
5704
    if (TSDB_CODE_SUCCESS != code) {
26,092,953✔
5705
      return code;
×
5706
    }
5707

5708
    // handle selectivity
5709
    if (pCtx->subsidiaries.num > 0) {
26,092,953✔
5710
      code = appendSelectivityValue(pCtx, i, pCtx->offset + numOfElems - 1);
821,992✔
5711
      if (TSDB_CODE_SUCCESS != code) {
821,992✔
5712
        return code;
×
5713
      }
5714
    }
5715
  }
5716

5717
  pResInfo->numOfRes = numOfElems;
379,048✔
5718
  return TSDB_CODE_SUCCESS;
379,048✔
5719
}
5720

5721
int32_t stateDurationFunction(SqlFunctionCtx* pCtx) {
935,086✔
5722
  int32_t              code = TSDB_CODE_SUCCESS;
935,086✔
5723
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
935,086✔
5724
  SStateInfo*          pInfo = GET_ROWCELL_INTERBUF(pResInfo);
935,086✔
5725

5726
  SInputColumnInfoData* pInput = &pCtx->input;
935,086✔
5727
  TSKEY*                tsList = (int64_t*)pInput->pPTS->pData;
935,086✔
5728

5729
  SColumnInfoData* pInputCol = pInput->pData[0];
935,086✔
5730

5731
  int32_t          numOfElems = 0;
935,086✔
5732
  SColumnInfoData* pOutput = (SColumnInfoData*)pCtx->pOutput;
935,086✔
5733

5734
  // TODO: process timeUnit for different db precisions
5735
  int32_t timeUnit = 1;
935,086✔
5736
  if (pCtx->numOfParams == 5) {  // TODO: param number incorrect
935,086✔
5737
    timeUnit = pCtx->param[3].param.i;
726,098✔
5738
  }
5739

5740
  int8_t op = getStateOpType(varDataVal(pCtx->param[1].param.pz));
935,086✔
5741
  if (STATE_OPER_INVALID == op) {
935,086✔
5742
    return TSDB_CODE_INVALID_PARA;
×
5743
  }
5744

5745
  for (int32_t i = pInput->startRowIndex; i < pInput->numOfRows + pInput->startRowIndex; i += 1) {
79,820,983✔
5746
    if (pInfo->isPrevTsSet == true && tsList[i] == pInfo->prevTs) {
78,886,725✔
5747
      return TSDB_CODE_FUNC_DUP_TIMESTAMP;
828✔
5748
    } else {
5749
      pInfo->prevTs = tsList[i];
78,885,897✔
5750
    }
5751

5752
    pInfo->isPrevTsSet = true;
78,885,897✔
5753
    numOfElems++;
78,885,897✔
5754

5755
    if (colDataIsNull_f(pInputCol, i)) {
78,885,897✔
5756
      colDataSetNULL(pOutput, i);
33,536,112✔
5757
      // handle selectivity
5758
      if (pCtx->subsidiaries.num > 0) {
33,536,112✔
5759
        code = appendSelectivityValue(pCtx, i, pCtx->offset + numOfElems - 1);
7,473✔
5760
        if (TSDB_CODE_SUCCESS != code) {
7,473✔
5761
          return code;
×
5762
        }
5763
      }
5764
      continue;
33,536,112✔
5765
    }
5766

5767
    bool    ret = checkStateOp(op, pInputCol, i, pCtx->param[2].param);
45,349,785✔
5768
    int64_t output = -1;
45,349,785✔
5769
    if (ret) {
45,349,785✔
5770
      if (pInfo->durationStart == 0) {
16,947,517✔
5771
        output = 0;
1,902,842✔
5772
        pInfo->durationStart = tsList[i];
1,902,842✔
5773
      } else {
5774
        output = (tsList[i] - pInfo->durationStart) / timeUnit;
15,044,675✔
5775
      }
5776
    } else {
5777
      pInfo->durationStart = 0;
28,402,268✔
5778
    }
5779
    code = colDataSetVal(pOutput, pCtx->offset + numOfElems - 1, (char*)&output, false);
45,349,785✔
5780
    if (TSDB_CODE_SUCCESS != code) {
45,349,785✔
5781
      return code;
×
5782
    }
5783

5784
    // handle selectivity
5785
    if (pCtx->subsidiaries.num > 0) {
45,349,785✔
5786
      code = appendSelectivityValue(pCtx, i, pCtx->offset + numOfElems - 1);
92,812✔
5787
      if (TSDB_CODE_SUCCESS != code) {
92,812✔
5788
        return code;
×
5789
      }
5790
    }
5791
  }
5792

5793
  pResInfo->numOfRes = numOfElems;
934,258✔
5794
  return TSDB_CODE_SUCCESS;
934,258✔
5795
}
5796

5797
bool getCsumFuncEnv(SFunctionNode* UNUSED_PARAM(pFunc), SFuncExecEnv* pEnv) {
646,046✔
5798
  pEnv->calcMemSize = sizeof(SSumRes);
646,046✔
5799
  return true;
646,046✔
5800
}
5801

5802
int32_t csumFunction(SqlFunctionCtx* pCtx) {
724,791✔
5803
  int32_t              code = TSDB_CODE_SUCCESS;
724,791✔
5804
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
724,791✔
5805
  SSumRes*             pSumRes = GET_ROWCELL_INTERBUF(pResInfo);
724,791✔
5806

5807
  SInputColumnInfoData* pInput = &pCtx->input;
724,791✔
5808
  TSKEY*                tsList = (int64_t*)pInput->pPTS->pData;
724,791✔
5809

5810
  SColumnInfoData* pInputCol = pInput->pData[0];
724,791✔
5811
  SColumnInfoData* pOutput = (SColumnInfoData*)pCtx->pOutput;
724,791✔
5812

5813
  int32_t numOfElems = 0;
724,791✔
5814
  int32_t type = pInputCol->info.type;
724,791✔
5815
  int32_t startOffset = pCtx->offset;
724,791✔
5816
  for (int32_t i = pInput->startRowIndex; i < pInput->numOfRows + pInput->startRowIndex; i += 1) {
121,487,467✔
5817
    if (pSumRes->isPrevTsSet == true && tsList[i] == pSumRes->prevTs) {
120,762,771✔
5818
      return TSDB_CODE_FUNC_DUP_TIMESTAMP;
7,011✔
5819
    } else {
5820
      pSumRes->prevTs = tsList[i];
120,753,380✔
5821
    }
5822
    pSumRes->isPrevTsSet = true;
120,755,032✔
5823

5824
    int32_t pos = startOffset + numOfElems;
120,753,520✔
5825
    if (colDataIsNull_f(pInputCol, i)) {
120,753,520✔
5826
      // colDataSetNULL(pOutput, i);
5827
      continue;
64,576,735✔
5828
    }
5829

5830
    char* data = colDataGetData(pInputCol, i);
56,185,941✔
5831
    if (IS_SIGNED_NUMERIC_TYPE(type)) {
95,798,350✔
5832
      int64_t v;
5833
      GET_TYPED_DATA(v, int64_t, type, data, typeGetTypeModFromColInfo(&pInputCol->info));
39,612,409✔
5834
      pSumRes->isum += v;
39,612,409✔
5835
      code = colDataSetVal(pOutput, pos, (char*)&pSumRes->isum, false);
39,612,409✔
5836
      if (TSDB_CODE_SUCCESS != code) {
39,612,409✔
5837
        return code;
×
5838
      }
5839
    } else if (IS_UNSIGNED_NUMERIC_TYPE(type)) {
26,370,740✔
5840
      uint64_t v;
5841
      GET_TYPED_DATA(v, uint64_t, type, data, typeGetTypeModFromColInfo(&pInputCol->info));
9,797,208✔
5842
      pSumRes->usum += v;
9,797,208✔
5843
      code = colDataSetVal(pOutput, pos, (char*)&pSumRes->usum, false);
9,797,208✔
5844
      if (TSDB_CODE_SUCCESS != code) {
9,797,208✔
5845
        return code;
×
5846
      }
5847
    } else if (IS_FLOAT_TYPE(type)) {
6,776,324✔
5848
      double v;
5849
      GET_TYPED_DATA(v, double, type, data, typeGetTypeModFromColInfo(&pInputCol->info));
6,776,324✔
5850
      pSumRes->dsum += v;
6,776,324✔
5851
      // check for overflow
5852
      if (isinf(pSumRes->dsum) || isnan(pSumRes->dsum)) {
6,776,324✔
5853
        colDataSetNULL(pOutput, pos);
864✔
5854
      } else {
5855
        code = colDataSetVal(pOutput, pos, (char*)&pSumRes->dsum, false);
6,775,460✔
5856
        if (TSDB_CODE_SUCCESS != code) {
6,775,460✔
5857
          return code;
×
5858
        }
5859
      }
5860
    }
5861

5862
    // handle selectivity
5863
    if (pCtx->subsidiaries.num > 0) {
56,185,941✔
5864
      code = appendSelectivityValue(pCtx, i, pos);
22,114✔
5865
      if (TSDB_CODE_SUCCESS != code) {
22,114✔
5866
        return code;
×
5867
      }
5868
    }
5869

5870
    numOfElems++;
56,185,941✔
5871
  }
5872

5873
  pResInfo->numOfRes = numOfElems;
717,780✔
5874
  return TSDB_CODE_SUCCESS;
717,780✔
5875
}
5876

5877
bool getMavgFuncEnv(SFunctionNode* UNUSED_PARAM(pFunc), SFuncExecEnv* pEnv) {
375,127✔
5878
  pEnv->calcMemSize = sizeof(SMavgInfo) + MAVG_MAX_POINTS_NUM * sizeof(double);
375,127✔
5879
  return true;
375,127✔
5880
}
5881

5882
int32_t mavgFunctionSetup(SqlFunctionCtx* pCtx, SResultRowEntryInfo* pResultInfo) {
833,025✔
5883
  if (pResultInfo->initialized) {
833,025✔
5884
    return TSDB_CODE_SUCCESS;
369,105✔
5885
  }
5886
  if (TSDB_CODE_SUCCESS != functionSetup(pCtx, pResultInfo)) {
463,920✔
5887
    return TSDB_CODE_FUNC_SETUP_ERROR;
×
5888
  }
5889

5890
  SMavgInfo* pInfo = GET_ROWCELL_INTERBUF(pResultInfo);
463,920✔
5891
  pInfo->pos = 0;
463,920✔
5892
  pInfo->sum = 0;
463,920✔
5893
  pInfo->prevTs = -1;
463,920✔
5894
  pInfo->isPrevTsSet = false;
463,920✔
5895
  pInfo->numOfPoints = pCtx->param[1].param.i;
463,920✔
5896
  if (pInfo->numOfPoints < 1 || pInfo->numOfPoints > MAVG_MAX_POINTS_NUM) {
463,920✔
5897
    return TSDB_CODE_FUNC_FUNTION_PARA_VALUE;
×
5898
  }
5899
  pInfo->pointsMeet = false;
463,920✔
5900

5901
  return TSDB_CODE_SUCCESS;
463,920✔
5902
}
5903

5904
int32_t mavgFunction(SqlFunctionCtx* pCtx) {
457,898✔
5905
  int32_t              code = TSDB_CODE_SUCCESS;
457,898✔
5906
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
457,898✔
5907
  SMavgInfo*           pInfo = GET_ROWCELL_INTERBUF(pResInfo);
457,898✔
5908

5909
  SInputColumnInfoData* pInput = &pCtx->input;
457,898✔
5910
  TSKEY*                tsList = (int64_t*)pInput->pPTS->pData;
457,898✔
5911

5912
  SColumnInfoData* pInputCol = pInput->pData[0];
457,898✔
5913
  SColumnInfoData* pTsOutput = pCtx->pTsOutput;
457,898✔
5914
  SColumnInfoData* pOutput = (SColumnInfoData*)pCtx->pOutput;
457,898✔
5915

5916
  int32_t numOfElems = 0;
457,898✔
5917
  int32_t type = pInputCol->info.type;
457,898✔
5918
  int32_t startOffset = pCtx->offset;
457,898✔
5919
  for (int32_t i = pInput->startRowIndex; i < pInput->numOfRows + pInput->startRowIndex; i += 1) {
118,275,432✔
5920
    if (pInfo->isPrevTsSet == true && tsList[i] == pInfo->prevTs) {
117,820,877✔
5921
      return TSDB_CODE_FUNC_DUP_TIMESTAMP;
828✔
5922
    } else {
5923
      pInfo->prevTs = tsList[i];
117,821,055✔
5924
    }
5925
    pInfo->isPrevTsSet = true;
117,825,079✔
5926

5927
    int32_t pos = startOffset + numOfElems;
117,825,079✔
5928
    if (colDataIsNull_f(pInputCol, i)) {
117,825,079✔
5929
      // colDataSetNULL(pOutput, i);
5930
      continue;
27,962,420✔
5931
    }
5932

5933
    char*  data = colDataGetData(pInputCol, i);
89,864,671✔
5934
    double v;
5935
    GET_TYPED_DATA(v, double, type, data, typeGetTypeModFromColInfo(&pInputCol->info));
89,864,671✔
5936

5937
    if (!pInfo->pointsMeet && (pInfo->pos < pInfo->numOfPoints - 1)) {
89,864,671✔
5938
      pInfo->points[pInfo->pos] = v;
39,241,953✔
5939
      pInfo->sum += v;
39,241,953✔
5940
    } else {
5941
      if (!pInfo->pointsMeet && (pInfo->pos == pInfo->numOfPoints - 1)) {
50,622,718✔
5942
        pInfo->sum += v;
101,726✔
5943
        pInfo->pointsMeet = true;
101,726✔
5944
      } else {
5945
        pInfo->sum = pInfo->sum + v - pInfo->points[pInfo->pos];
50,520,992✔
5946
      }
5947

5948
      pInfo->points[pInfo->pos] = v;
50,622,718✔
5949
      double result = pInfo->sum / pInfo->numOfPoints;
50,622,718✔
5950
      // check for overflow
5951
      if (isinf(result) || isnan(result)) {
50,622,718✔
5952
        colDataSetNULL(pOutput, pos);
×
5953
      } else {
5954
        code = colDataSetVal(pOutput, pos, (char*)&result, false);
50,622,718✔
5955
        if (TSDB_CODE_SUCCESS != code) {
50,622,718✔
5956
          return code;
×
5957
        }
5958
      }
5959

5960
      // handle selectivity
5961
      if (pCtx->subsidiaries.num > 0) {
50,622,718✔
5962
        code = appendSelectivityValue(pCtx, i, pos);
32,312✔
5963
        if (TSDB_CODE_SUCCESS != code) {
32,312✔
5964
          return code;
×
5965
        }
5966
      }
5967

5968
      numOfElems++;
50,622,718✔
5969
    }
5970

5971
    pInfo->pos++;
89,864,671✔
5972
    if (pInfo->pos == pInfo->numOfPoints) {
89,864,671✔
5973
      pInfo->pos = 0;
706,869✔
5974
    }
5975
  }
5976

5977
  pResInfo->numOfRes = numOfElems;
457,070✔
5978
  return TSDB_CODE_SUCCESS;
457,070✔
5979
}
5980

5981
static SSampleInfo* getSampleOutputInfo(SqlFunctionCtx* pCtx) {
3,702,675✔
5982
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
3,702,675✔
5983
  SSampleInfo*         pInfo = GET_ROWCELL_INTERBUF(pResInfo);
3,702,675✔
5984

5985
  pInfo->data = (char*)pInfo + sizeof(SSampleInfo);
3,702,675✔
5986
  pInfo->tuplePos = (STuplePos*)((char*)pInfo + sizeof(SSampleInfo) + pInfo->samples * pInfo->colBytes);
3,702,675✔
5987

5988
  return pInfo;
3,702,675✔
5989
}
5990

5991
bool getSampleFuncEnv(SFunctionNode* pFunc, SFuncExecEnv* pEnv) {
770,155✔
5992
  SColumnNode* pCol = (SColumnNode*)nodesListGetNode(pFunc->pParameterList, 0);
770,155✔
5993
  SValueNode*  pVal = (SValueNode*)nodesListGetNode(pFunc->pParameterList, 1);
770,155✔
5994
  int32_t      numOfSamples = pVal->datum.i;
768,419✔
5995
  pEnv->calcMemSize = sizeof(SSampleInfo) + numOfSamples * (pCol->node.resType.bytes + sizeof(STuplePos));
768,419✔
5996
  return true;
768,914✔
5997
}
5998

5999
int32_t sampleFunctionSetup(SqlFunctionCtx* pCtx, SResultRowEntryInfo* pResultInfo) {
1,690,146✔
6000
  if (pResultInfo->initialized) {
1,690,146✔
6001
    return TSDB_CODE_SUCCESS;
×
6002
  }
6003
  if (TSDB_CODE_SUCCESS != functionSetup(pCtx, pResultInfo)) {
1,690,146✔
6004
    return TSDB_CODE_FUNC_SETUP_ERROR;
×
6005
  }
6006

6007
  taosSeedRand(taosSafeRand());
1,690,146✔
6008

6009
  SSampleInfo* pInfo = GET_ROWCELL_INTERBUF(pResultInfo);
1,690,146✔
6010
  pInfo->samples = pCtx->param[1].param.i;
1,690,146✔
6011
  pInfo->totalPoints = 0;
1,690,146✔
6012
  pInfo->numSampled = 0;
1,690,146✔
6013
  pInfo->colType = pCtx->resDataInfo.type;
1,690,146✔
6014
  pInfo->colBytes = pCtx->resDataInfo.bytes;
1,690,146✔
6015
  pInfo->nullTuplePos.pageId = -1;
1,690,146✔
6016
  pInfo->nullTupleSaved = false;
1,690,146✔
6017
  pInfo->data = (char*)pInfo + sizeof(SSampleInfo);
1,690,146✔
6018
  pInfo->tuplePos = (STuplePos*)((char*)pInfo + sizeof(SSampleInfo) + pInfo->samples * pInfo->colBytes);
1,690,146✔
6019

6020
  return TSDB_CODE_SUCCESS;
1,690,146✔
6021
}
6022

6023
static void sampleAssignResult(SSampleInfo* pInfo, char* data, int32_t index) {
82,428,556✔
6024
  assignVal(pInfo->data + index * pInfo->colBytes, data, pInfo->colBytes, pInfo->colType);
82,428,556✔
6025
}
82,428,920✔
6026

6027
static int32_t doReservoirSample(SqlFunctionCtx* pCtx, SSampleInfo* pInfo, char* data, int32_t index) {
117,319,335✔
6028
  pInfo->totalPoints++;
117,319,335✔
6029
  if (pInfo->numSampled < pInfo->samples) {
117,319,335✔
6030
    sampleAssignResult(pInfo, data, pInfo->numSampled);
80,906,599✔
6031
    if (pCtx->subsidiaries.num > 0) {
80,906,599✔
6032
      int32_t code = saveTupleData(pCtx, index, pCtx->pSrcBlock, &pInfo->tuplePos[pInfo->numSampled]);
987,888✔
6033
      if (code != TSDB_CODE_SUCCESS) {
987,888✔
6034
        return code;
×
6035
      }
6036
    }
6037
    pInfo->numSampled++;
80,906,599✔
6038
  } else {
6039
    int32_t j = taosRand() % (pInfo->totalPoints);
36,413,525✔
6040
    if (j < pInfo->samples) {
36,413,525✔
6041
      sampleAssignResult(pInfo, data, j);
1,522,321✔
6042
      if (pCtx->subsidiaries.num > 0) {
1,522,321✔
6043
        int32_t code = updateTupleData(pCtx, index, pCtx->pSrcBlock, &pInfo->tuplePos[j]);
334,015✔
6044
        if (code != TSDB_CODE_SUCCESS) {
334,015✔
6045
          return code;
×
6046
        }
6047
      }
6048
    }
6049
  }
6050

6051
  return TSDB_CODE_SUCCESS;
117,320,124✔
6052
}
6053

6054
int32_t sampleFunction(SqlFunctionCtx* pCtx) {
2,015,013✔
6055
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
2,015,013✔
6056
  SSampleInfo*         pInfo = getSampleOutputInfo(pCtx);
2,015,013✔
6057

6058
  SInputColumnInfoData* pInput = &pCtx->input;
2,015,013✔
6059

6060
  SColumnInfoData* pInputCol = pInput->pData[0];
2,015,013✔
6061
  for (int32_t i = pInput->startRowIndex; i < pInput->numOfRows + pInput->startRowIndex; i += 1) {
145,874,412✔
6062
    if (colDataIsNull_s(pInputCol, i)) {
287,676,322✔
6063
      continue;
26,539,275✔
6064
    }
6065

6066
    char*   data = colDataGetData(pInputCol, i);
117,320,488✔
6067
    int32_t code = doReservoirSample(pCtx, pInfo, data, i);
117,319,699✔
6068
    if (code != TSDB_CODE_SUCCESS) {
117,320,124✔
6069
      return code;
×
6070
    }
6071
  }
6072

6073
  if (pInfo->numSampled == 0 && pCtx->subsidiaries.num > 0 && !pInfo->nullTupleSaved) {
2,015,013✔
6074
    int32_t code = saveTupleData(pCtx, pInput->startRowIndex, pCtx->pSrcBlock, &pInfo->nullTuplePos);
1,700✔
6075
    if (code != TSDB_CODE_SUCCESS) {
1,700✔
6076
      return code;
×
6077
    }
6078
    pInfo->nullTupleSaved = true;
1,700✔
6079
  }
6080

6081
  SET_VAL(pResInfo, pInfo->numSampled, pInfo->numSampled);
2,015,013✔
6082
  return TSDB_CODE_SUCCESS;
2,015,013✔
6083
}
6084

6085
int32_t sampleFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
1,687,662✔
6086
  int32_t              code = TSDB_CODE_SUCCESS;
1,687,662✔
6087
  SResultRowEntryInfo* pEntryInfo = GET_RES_INFO(pCtx);
1,687,662✔
6088

6089
  SSampleInfo* pInfo = getSampleOutputInfo(pCtx);
1,687,662✔
6090
  pEntryInfo->complete = true;
1,687,662✔
6091

6092
  int32_t          slotId = pCtx->pExpr->base.resSchema.slotId;
1,687,662✔
6093
  SColumnInfoData* pCol = taosArrayGet(pBlock->pDataBlock, slotId);
1,687,662✔
6094
  if (NULL == pCol) {
1,687,662✔
6095
    return TSDB_CODE_OUT_OF_RANGE;
×
6096
  }
6097

6098
  int32_t currentRow = pBlock->info.rows;
1,687,662✔
6099
  if (pInfo->numSampled == 0) {
1,687,662✔
6100
    colDataSetNULL(pCol, currentRow);
183,986✔
6101
    code = setSelectivityValue(pCtx, pBlock, &pInfo->nullTuplePos, currentRow);
183,986✔
6102
    return code;
183,986✔
6103
  }
6104
  for (int32_t i = 0; i < pInfo->numSampled; ++i) {
82,404,779✔
6105
    code = colDataSetVal(pCol, currentRow + i, pInfo->data + i * pInfo->colBytes, false);
80,900,757✔
6106
    if (TSDB_CODE_SUCCESS != code) {
80,901,494✔
6107
      return code;
×
6108
    }
6109
    code = setSelectivityValue(pCtx, pBlock, &pInfo->tuplePos[i], currentRow + i);
80,901,494✔
6110
    if (TSDB_CODE_SUCCESS != code) {
80,901,103✔
6111
      return code;
×
6112
    }
6113
  }
6114

6115
  return code;
1,503,676✔
6116
}
6117

6118
bool getTailFuncEnv(SFunctionNode* pFunc, SFuncExecEnv* pEnv) {
×
6119
#if 0
6120
  SColumnNode* pCol = (SColumnNode*)nodesListGetNode(pFunc->pParameterList, 0);
6121
  SValueNode*  pVal = (SValueNode*)nodesListGetNode(pFunc->pParameterList, 1);
6122
  int32_t      numOfPoints = pVal->datum.i;
6123
  pEnv->calcMemSize = sizeof(STailInfo) + numOfPoints * (POINTER_BYTES + sizeof(STailItem) + pCol->node.resType.bytes);
6124
#endif
6125
  return true;
×
6126
}
6127

6128
int32_t tailFunctionSetup(SqlFunctionCtx* pCtx, SResultRowEntryInfo* pResultInfo) {
×
6129
#if 0
6130
  if (!functionSetup(pCtx, pResultInfo)) {
6131
    return false;
6132
  }
6133

6134
  STailInfo* pInfo = GET_ROWCELL_INTERBUF(pResultInfo);
6135
  pInfo->numAdded = 0;
6136
  pInfo->numOfPoints = pCtx->param[1].param.i;
6137
  if (pCtx->numOfParams == 4) {
6138
    pInfo->offset = pCtx->param[2].param.i;
6139
  } else {
6140
    pInfo->offset = 0;
6141
  }
6142
  pInfo->colType = pCtx->resDataInfo.type;
6143
  pInfo->colBytes = pCtx->resDataInfo.bytes;
6144
  if ((pInfo->numOfPoints < 1 || pInfo->numOfPoints > TAIL_MAX_POINTS_NUM) ||
6145
      (pInfo->numOfPoints < 0 || pInfo->numOfPoints > TAIL_MAX_OFFSET)) {
6146
    return false;
6147
  }
6148

6149
  pInfo->pItems = (STailItem**)((char*)pInfo + sizeof(STailInfo));
6150
  char* pItem = (char*)pInfo->pItems + pInfo->numOfPoints * POINTER_BYTES;
6151

6152
  size_t unitSize = sizeof(STailItem) + pInfo->colBytes;
6153
  for (int32_t i = 0; i < pInfo->numOfPoints; ++i) {
6154
    pInfo->pItems[i] = (STailItem*)(pItem + i * unitSize);
6155
    pInfo->pItems[i]->isNull = false;
6156
  }
6157
#endif
6158
  return TSDB_CODE_SUCCESS;
×
6159
}
6160

6161
static void tailAssignResult(STailItem* pItem, char* data, int32_t colBytes, TSKEY ts, bool isNull) {
×
6162
#if 0
6163
  pItem->timestamp = ts;
6164
  if (isNull) {
6165
    pItem->isNull = true;
6166
  } else {
6167
    pItem->isNull = false;
6168
    memcpy(pItem->data, data, colBytes);
6169
  }
6170
#endif
6171
}
×
6172

6173
#if 0
6174
static int32_t tailCompFn(const void* p1, const void* p2, const void* param) {
6175
  STailItem* d1 = *(STailItem**)p1;
6176
  STailItem* d2 = *(STailItem**)p2;
6177
  return compareInt64Val(&d1->timestamp, &d2->timestamp);
6178
}
6179

6180
static void doTailAdd(STailInfo* pInfo, char* data, TSKEY ts, bool isNull) {
6181
  STailItem** pList = pInfo->pItems;
6182
  if (pInfo->numAdded < pInfo->numOfPoints) {
6183
    tailAssignResult(pList[pInfo->numAdded], data, pInfo->colBytes, ts, isNull);
6184
    taosheapsort((void*)pList, sizeof(STailItem**), pInfo->numAdded + 1, NULL, tailCompFn, 0);
6185
    pInfo->numAdded++;
6186
  } else if (pList[0]->timestamp < ts) {
6187
    tailAssignResult(pList[0], data, pInfo->colBytes, ts, isNull);
6188
    taosheapadjust((void*)pList, sizeof(STailItem**), 0, pInfo->numOfPoints - 1, NULL, tailCompFn, NULL, 0);
6189
  }
6190
}
6191
#endif
6192

6193
int32_t tailFunction(SqlFunctionCtx* pCtx) {
×
6194
#if 0
6195
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
6196
  STailInfo*           pInfo = GET_ROWCELL_INTERBUF(pResInfo);
6197

6198
  SInputColumnInfoData* pInput = &pCtx->input;
6199
  TSKEY*                tsList = (int64_t*)pInput->pPTS->pData;
6200

6201
  SColumnInfoData* pInputCol = pInput->pData[0];
6202
  SColumnInfoData* pOutput = (SColumnInfoData*)pCtx->pOutput;
6203

6204
  int32_t startOffset = pCtx->offset;
6205
  if (pInfo->offset >= pInput->numOfRows) {
6206
    return 0;
6207
  } else {
6208
    pInfo->numOfPoints = TMIN(pInfo->numOfPoints, pInput->numOfRows - pInfo->offset);
6209
  }
6210
  for (int32_t i = pInput->startRowIndex; i < pInput->numOfRows + pInput->startRowIndex - pInfo->offset; i += 1) {
6211
    char* data = colDataGetData(pInputCol, i);
6212
    doTailAdd(pInfo, data, tsList[i], colDataIsNull_s(pInputCol, i));
6213
  }
6214

6215
  taosqsort(pInfo->pItems, pInfo->numOfPoints, POINTER_BYTES, NULL, tailCompFn);
6216

6217
  for (int32_t i = 0; i < pInfo->numOfPoints; ++i) {
6218
    int32_t    pos = startOffset + i;
6219
    STailItem* pItem = pInfo->pItems[i];
6220
    if (pItem->isNull) {
6221
      colDataSetNULL(pOutput, pos);
6222
    } else {
6223
      colDataSetVal(pOutput, pos, pItem->data, false);
6224
    }
6225
  }
6226

6227
  return pInfo->numOfPoints;
6228
#endif
6229
  return 0;
×
6230
}
6231

6232
int32_t tailFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
×
6233
#if 0
6234
  SResultRowEntryInfo* pEntryInfo = GET_RES_INFO(pCtx);
6235
  STailInfo*           pInfo = GET_ROWCELL_INTERBUF(pEntryInfo);
6236
  pEntryInfo->complete = true;
6237

6238
  int32_t type = pCtx->input.pData[0]->info.type;
6239
  int32_t slotId = pCtx->pExpr->base.resSchema.slotId;
6240

6241
  SColumnInfoData* pCol = taosArrayGet(pBlock->pDataBlock, slotId);
6242

6243
  // todo assign the tag value and the corresponding row data
6244
  int32_t currentRow = pBlock->info.rows;
6245
  for (int32_t i = 0; i < pEntryInfo->numOfRes; ++i) {
6246
    STailItem* pItem = pInfo->pItems[i];
6247
    colDataSetVal(pCol, currentRow, pItem->data, false);
6248
    currentRow += 1;
6249
  }
6250

6251
  return pEntryInfo->numOfRes;
6252
#endif
6253
  return 0;
×
6254
}
6255

6256
bool getUniqueFuncEnv(SFunctionNode* pFunc, SFuncExecEnv* pEnv) {
×
6257
#if 0
6258
  pEnv->calcMemSize = sizeof(SUniqueInfo) + UNIQUE_MAX_RESULT_SIZE;
6259
#endif
6260
  return true;
×
6261
}
6262

6263
int32_t uniqueFunctionSetup(SqlFunctionCtx* pCtx, SResultRowEntryInfo* pResInfo) {
×
6264
#if 0
6265
  if (!functionSetup(pCtx, pResInfo)) {
6266
    return false;
6267
  }
6268

6269
  SUniqueInfo* pInfo = GET_ROWCELL_INTERBUF(pResInfo);
6270
  pInfo->numOfPoints = 0;
6271
  pInfo->colType = pCtx->resDataInfo.type;
6272
  pInfo->colBytes = pCtx->resDataInfo.bytes;
6273
  if (pInfo->pHash != NULL) {
6274
    taosHashClear(pInfo->pHash);
6275
  } else {
6276
    pInfo->pHash = taosHashInit(64, taosGetDefaultHashFunction(TSDB_DATA_TYPE_BINARY), true, HASH_NO_LOCK);
6277
  }
6278
#endif
6279
  return TSDB_CODE_SUCCESS;
×
6280
}
6281

6282
#if 0
6283
static void doUniqueAdd(SUniqueInfo* pInfo, char* data, TSKEY ts, bool isNull) {
6284
  // handle null elements
6285
  if (isNull == true) {
6286
    int32_t      size = sizeof(SUniqueItem) + pInfo->colBytes;
6287
    SUniqueItem* pItem = (SUniqueItem*)(pInfo->pItems + pInfo->numOfPoints * size);
6288
    if (pInfo->hasNull == false && pItem->isNull == false) {
6289
      pItem->timestamp = ts;
6290
      pItem->isNull = true;
6291
      pInfo->numOfPoints++;
6292
      pInfo->hasNull = true;
6293
    } else if (pItem->timestamp > ts && pItem->isNull == true) {
6294
      pItem->timestamp = ts;
6295
    }
6296
    return;
6297
  }
6298

6299
  int32_t      hashKeyBytes = IS_VAR_DATA_TYPE(pInfo->colType) ? varDataTLen(data) : pInfo->colBytes;
6300
  SUniqueItem* pHashItem = taosHashGet(pInfo->pHash, data, hashKeyBytes);
6301
  if (pHashItem == NULL) {
6302
    int32_t      size = sizeof(SUniqueItem) + pInfo->colBytes;
6303
    SUniqueItem* pItem = (SUniqueItem*)(pInfo->pItems + pInfo->numOfPoints * size);
6304
    pItem->timestamp = ts;
6305
    memcpy(pItem->data, data, pInfo->colBytes);
6306

6307
    taosHashPut(pInfo->pHash, data, hashKeyBytes, (char*)pItem, sizeof(SUniqueItem*));
6308
    pInfo->numOfPoints++;
6309
  } else if (pHashItem->timestamp > ts) {
6310
    pHashItem->timestamp = ts;
6311
  }
6312
}
6313
#endif
6314

6315
int32_t uniqueFunction(SqlFunctionCtx* pCtx) {
×
6316
#if 0
6317
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
6318
  SUniqueInfo*         pInfo = GET_ROWCELL_INTERBUF(pResInfo);
6319

6320
  SInputColumnInfoData* pInput = &pCtx->input;
6321
  TSKEY*                tsList = (int64_t*)pInput->pPTS->pData;
6322

6323
  SColumnInfoData* pInputCol = pInput->pData[0];
6324
  SColumnInfoData* pTsOutput = pCtx->pTsOutput;
6325
  SColumnInfoData* pOutput = (SColumnInfoData*)pCtx->pOutput;
6326

6327
  int32_t startOffset = pCtx->offset;
6328
  for (int32_t i = pInput->startRowIndex; i < pInput->numOfRows + pInput->startRowIndex; ++i) {
6329
    char* data = colDataGetData(pInputCol, i);
6330
    doUniqueAdd(pInfo, data, tsList[i], colDataIsNull_s(pInputCol, i));
6331

6332
    if (sizeof(SUniqueInfo) + pInfo->numOfPoints * (sizeof(SUniqueItem) + pInfo->colBytes) >= UNIQUE_MAX_RESULT_SIZE) {
6333
      taosHashCleanup(pInfo->pHash);
6334
      return 0;
6335
    }
6336
  }
6337

6338
  for (int32_t i = 0; i < pInfo->numOfPoints; ++i) {
6339
    SUniqueItem* pItem = (SUniqueItem*)(pInfo->pItems + i * (sizeof(SUniqueItem) + pInfo->colBytes));
6340
    if (pItem->isNull == true) {
6341
      colDataSetNULL(pOutput, i);
6342
    } else {
6343
      colDataSetVal(pOutput, i, pItem->data, false);
6344
    }
6345
    if (pTsOutput != NULL) {
6346
      colDataSetInt64(pTsOutput, i, &pItem->timestamp);
6347
    }
6348
  }
6349

6350
  return pInfo->numOfPoints;
6351
#endif
6352
  return 0;
×
6353
}
6354

6355
bool getModeFuncEnv(SFunctionNode* pFunc, SFuncExecEnv* pEnv) {
1,218,228✔
6356
  pEnv->calcMemSize = sizeof(SModeInfo);
1,218,228✔
6357
  return true;
1,218,732✔
6358
}
6359

6360
int32_t modeFunctionSetup(SqlFunctionCtx* pCtx, SResultRowEntryInfo* pResInfo) {
2,026,212✔
6361
  if (pResInfo->initialized) {
2,026,212✔
6362
    return TSDB_CODE_SUCCESS;
×
6363
  }
6364
  if (TSDB_CODE_SUCCESS != functionSetup(pCtx, pResInfo)) {
2,025,848✔
6365
    return TSDB_CODE_FUNC_SETUP_ERROR;
×
6366
  }
6367

6368
  SModeInfo* pInfo = GET_ROWCELL_INTERBUF(pResInfo);
2,025,848✔
6369
  pInfo->colType = pCtx->resDataInfo.type;
2,025,848✔
6370
  pInfo->colBytes = pCtx->resDataInfo.bytes;
2,026,212✔
6371
  if (pInfo->pHash != NULL) {
2,026,212✔
6372
    taosHashClear(pInfo->pHash);
×
6373
  } else {
6374
    pInfo->pHash = taosHashInit(64, taosGetDefaultHashFunction(TSDB_DATA_TYPE_BINARY), true, HASH_NO_LOCK);
2,026,212✔
6375
    if (NULL == pInfo->pHash) {
2,026,212✔
6376
      return terrno;
×
6377
    }
6378
  }
6379
  pInfo->nullTupleSaved = false;
2,026,212✔
6380
  pInfo->nullTuplePos.pageId = -1;
2,026,212✔
6381

6382
  pInfo->buf = taosMemoryMalloc(pInfo->colBytes);
2,026,212✔
6383
  if (NULL == pInfo->buf) {
2,026,212✔
6384
    taosHashCleanup(pInfo->pHash);
×
6385
    pInfo->pHash = NULL;
×
6386
    return terrno;
×
6387
  }
6388
  pCtx->needCleanup = true;
2,026,212✔
6389
  return TSDB_CODE_SUCCESS;
2,026,212✔
6390
}
6391

6392
static void modeFunctionCleanup(SModeInfo* pInfo) {
3,176,834✔
6393
  taosHashCleanup(pInfo->pHash);
3,176,834✔
6394
  pInfo->pHash = NULL;
3,177,198✔
6395
  taosMemoryFreeClear(pInfo->buf);
3,177,198✔
6396
}
3,176,834✔
6397

6398
void modeFunctionCleanupExt(SqlFunctionCtx* pCtx) {
1,218,872✔
6399
  if (pCtx == NULL || GET_RES_INFO(pCtx) == NULL || GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx)) == NULL) {
1,218,872✔
6400
    return;
67,008✔
6401
  }
6402
  modeFunctionCleanup(GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx)));
1,151,500✔
6403
}
6404

6405
static int32_t saveModeTupleData(SqlFunctionCtx* pCtx, char* data, SModeInfo* pInfo, STuplePos* pPos) {
2,147,483,647✔
6406
  if (IS_VAR_DATA_TYPE(pInfo->colType)) {
2,147,483,647✔
6407
    if (pInfo->colType == TSDB_DATA_TYPE_JSON) {
2,531,424✔
6408
      (void)memcpy(pInfo->buf, data, getJsonValueLen(data));
266,112✔
6409
    } else if (IS_STR_DATA_BLOB(pInfo->colType)) {
2,265,726✔
6410
      (void)memcpy(pInfo->buf, data, blobDataTLen(data));
×
6411
    } else {
6412
      (void)memcpy(pInfo->buf, data, varDataTLen(data));
2,265,726✔
6413
    }
6414
  } else {
6415
    (void)memcpy(pInfo->buf, data, pInfo->colBytes);
2,147,483,647✔
6416
  }
6417

6418
  return doSaveTupleData(&pCtx->saveHandle, pInfo->buf, pInfo->colBytes, NULL, pPos, pCtx->pStore);
2,147,483,647✔
6419
}
6420

6421
static int32_t doModeAdd(SModeInfo* pInfo, int32_t rowIndex, SqlFunctionCtx* pCtx, char* data) {
2,147,483,647✔
6422
  int32_t code = TSDB_CODE_SUCCESS;
2,147,483,647✔
6423
  int32_t hashKeyBytes;
6424
  if (IS_VAR_DATA_TYPE(pInfo->colType)) {
2,147,483,647✔
6425
    hashKeyBytes = calcStrBytesByType(pInfo->colType, data);
2,147,483,647✔
6426
  } else {
6427
    hashKeyBytes = pInfo->colBytes;
2,147,483,647✔
6428
  }
6429

6430
  SModeItem* pHashItem = (SModeItem*)taosHashGet(pInfo->pHash, data, hashKeyBytes);
2,147,483,647✔
6431
  if (pHashItem == NULL) {
2,147,483,647✔
6432
    int32_t   size = sizeof(SModeItem);
2,147,483,647✔
6433
    SModeItem item = {0};
2,147,483,647✔
6434

6435
    item.count += 1;
2,147,483,647✔
6436
    code = saveModeTupleData(pCtx, data, pInfo, &item.dataPos);
2,147,483,647✔
6437
    if (code != TSDB_CODE_SUCCESS) {
2,147,483,647✔
6438
      return code;
×
6439
    }
6440

6441
    if (pCtx->subsidiaries.num > 0) {
2,147,483,647✔
6442
      code = saveTupleData(pCtx, rowIndex, pCtx->pSrcBlock, &item.tuplePos);
258,581✔
6443
      if (code != TSDB_CODE_SUCCESS) {
258,581✔
6444
        return code;
×
6445
      }
6446
    }
6447

6448
    code = taosHashPut(pInfo->pHash, data, hashKeyBytes, &item, sizeof(SModeItem));
2,147,483,647✔
6449
    if (code != TSDB_CODE_SUCCESS) {
2,147,483,647✔
6450
      return code;
×
6451
    }
6452
  } else {
6453
    pHashItem->count += 1;
2,147,483,647✔
6454
    if (pCtx->subsidiaries.num > 0) {
2,147,483,647✔
6455
      code = updateTupleData(pCtx, rowIndex, pCtx->pSrcBlock, &pHashItem->tuplePos);
3,380,749✔
6456
      if (code != TSDB_CODE_SUCCESS) {
3,380,749✔
6457
        return code;
×
6458
      }
6459
    }
6460
  }
6461

6462
  return code;
2,147,483,647✔
6463
}
6464

6465
int32_t modeFunction(SqlFunctionCtx* pCtx) {
2,147,483,647✔
6466
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
2,147,483,647✔
6467
  SModeInfo*           pInfo = GET_ROWCELL_INTERBUF(pResInfo);
2,147,483,647✔
6468

6469
  SInputColumnInfoData* pInput = &pCtx->input;
2,147,483,647✔
6470

6471
  SColumnInfoData* pInputCol = pInput->pData[0];
2,147,483,647✔
6472
  SColumnInfoData* pOutput = (SColumnInfoData*)pCtx->pOutput;
2,147,483,647✔
6473

6474
  int32_t numOfElems = 0;
2,147,483,647✔
6475
  int32_t startOffset = pCtx->offset;
2,147,483,647✔
6476
  for (int32_t i = pInput->startRowIndex; i < pInput->numOfRows + pInput->startRowIndex; ++i) {
2,147,483,647✔
6477
    if (colDataIsNull_s(pInputCol, i)) {
2,147,483,647✔
6478
      continue;
2,147,483,647✔
6479
    }
6480
    numOfElems++;
2,147,483,647✔
6481

6482
    char*   data = colDataGetData(pInputCol, i);
2,147,483,647✔
6483
    int32_t code = doModeAdd(pInfo, i, pCtx, data);
2,147,483,647✔
6484
    if (code != TSDB_CODE_SUCCESS) {
2,147,483,647✔
6485
      modeFunctionCleanup(pInfo);
495✔
6486
      return code;
×
6487
    }
6488
  }
6489

6490
  if (numOfElems == 0 && pCtx->subsidiaries.num > 0 && !pInfo->nullTupleSaved) {
2,147,483,647✔
6491
    int32_t code = saveTupleData(pCtx, pInput->startRowIndex, pCtx->pSrcBlock, &pInfo->nullTuplePos);
4,350✔
6492
    if (code != TSDB_CODE_SUCCESS) {
4,350✔
6493
      modeFunctionCleanup(pInfo);
×
6494
      return code;
×
6495
    }
6496
    pInfo->nullTupleSaved = true;
4,350✔
6497
  }
6498

6499
  SET_VAL(pResInfo, numOfElems, 1);
2,147,483,647✔
6500

6501
  return TSDB_CODE_SUCCESS;
2,147,483,647✔
6502
}
6503

6504
int32_t modeFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
2,024,970✔
6505
  int32_t              code = TSDB_CODE_SUCCESS;
2,024,970✔
6506
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
2,024,970✔
6507
  SModeInfo*           pInfo = GET_ROWCELL_INTERBUF(pResInfo);
2,024,242✔
6508
  int32_t              slotId = pCtx->pExpr->base.resSchema.slotId;
2,024,970✔
6509
  SColumnInfoData*     pCol = taosArrayGet(pBlock->pDataBlock, slotId);
2,024,606✔
6510
  int32_t              currentRow = pBlock->info.rows;
2,024,970✔
6511
  if (NULL == pCol) {
2,024,970✔
6512
    modeFunctionCleanup(pInfo);
×
6513
    return TSDB_CODE_OUT_OF_RANGE;
×
6514
  }
6515

6516
  STuplePos resDataPos, resTuplePos;
2,024,970✔
6517
  int32_t   maxCount = 0;
2,024,606✔
6518

6519
  void* pIter = taosHashIterate(pInfo->pHash, NULL);
2,024,606✔
6520
  while (pIter != NULL) {
2,147,483,647✔
6521
    SModeItem* pItem = (SModeItem*)pIter;
2,147,483,647✔
6522
    if (pItem->count >= maxCount) {
2,147,483,647✔
6523
      maxCount = pItem->count;
1,951,042,916✔
6524
      resDataPos = pItem->dataPos;
1,951,042,916✔
6525
      resTuplePos = pItem->tuplePos;
1,951,042,916✔
6526
    }
6527

6528
    pIter = taosHashIterate(pInfo->pHash, pIter);
2,147,483,647✔
6529
  }
6530

6531
  if (maxCount != 0) {
2,024,970✔
6532
    char* pData = NULL;
1,610,286✔
6533
    code = loadTupleData(pCtx, &resDataPos, &pData);
1,610,286✔
6534
    if (pData == NULL || TSDB_CODE_SUCCESS != code) {
1,610,286✔
6535
      code = terrno = TSDB_CODE_NOT_FOUND;
×
6536
      qError("Load tuple data failed since %s, groupId:%" PRIu64 ", ts:%" PRId64, terrstr(),
×
6537
             resDataPos.streamTupleKey.groupId, resDataPos.streamTupleKey.ts);
6538
      modeFunctionCleanup(pInfo);
×
6539
      return code;
×
6540
    }
6541

6542
    code = colDataSetVal(pCol, currentRow, pData, false);
1,610,286✔
6543
    if (TSDB_CODE_SUCCESS != code) {
1,610,286✔
6544
      modeFunctionCleanup(pInfo);
×
6545
      return code;
×
6546
    }
6547
    code = setSelectivityValue(pCtx, pBlock, &resTuplePos, currentRow);
1,610,286✔
6548
  } else {
6549
    colDataSetNULL(pCol, currentRow);
414,684✔
6550
    code = setSelectivityValue(pCtx, pBlock, &pInfo->nullTuplePos, currentRow);
414,684✔
6551
  }
6552

6553
  modeFunctionCleanup(pInfo);
2,024,606✔
6554

6555
  return code;
2,024,970✔
6556
}
6557

6558
bool getTwaFuncEnv(struct SFunctionNode* pFunc, SFuncExecEnv* pEnv) {
296,558✔
6559
  pEnv->calcMemSize = sizeof(STwaInfo);
296,558✔
6560
  return true;
296,983✔
6561
}
6562

6563
int32_t twaFunctionSetup(SqlFunctionCtx* pCtx, SResultRowEntryInfo* pResultInfo) {
6,978,018✔
6564
  if (pResultInfo->initialized) {
6,978,018✔
6565
    return TSDB_CODE_SUCCESS;
×
6566
  }
6567
  if (TSDB_CODE_SUCCESS != functionSetup(pCtx, pResultInfo)) {
6,978,443✔
6568
    return TSDB_CODE_FUNC_SETUP_ERROR;
×
6569
  }
6570

6571
  STwaInfo* pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
6,978,443✔
6572
  pInfo->numOfElems = 0;
6,978,443✔
6573
  pInfo->p.key = INT64_MIN;
6,978,443✔
6574
  pInfo->win = TSWINDOW_INITIALIZER;
6,978,443✔
6575
  return TSDB_CODE_SUCCESS;
6,978,443✔
6576
}
6577

6578
static double twa_get_area(SPoint1 s, SPoint1 e) {
180,689,839✔
6579
  if (e.key == INT64_MAX || s.key == INT64_MIN) {
180,689,839✔
6580
    return 0;
×
6581
  }
6582

6583
  if ((s.val >= 0 && e.val >= 0) || (s.val <= 0 && e.val <= 0)) {
180,766,036✔
6584
    return (s.val + e.val) * (e.key - s.key) / 2;
164,135,069✔
6585
  }
6586

6587
  double x = (s.key * e.val - e.key * s.val) / (e.val - s.val);
16,630,967✔
6588
  double val = (s.val * (x - s.key) + e.val * (e.key - x)) / 2;
16,630,967✔
6589
  return val;
16,630,967✔
6590
}
6591

6592
int32_t twaFunction(SqlFunctionCtx* pCtx) {
7,025,685✔
6593
  int32_t               code = TSDB_CODE_SUCCESS;
7,025,685✔
6594
  SInputColumnInfoData* pInput = &pCtx->input;
7,025,685✔
6595
  SColumnInfoData*      pInputCol = pInput->pData[0];
7,025,685✔
6596

6597
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
7,025,685✔
6598
  STwaInfo*            pInfo = GET_ROWCELL_INTERBUF(pResInfo);
7,025,685✔
6599
  SPoint1*             last = &pInfo->p;
7,025,685✔
6600

6601
  if (IS_NULL_TYPE(pInputCol->info.type)) {
7,025,685✔
6602
    pInfo->numOfElems = 0;
×
6603
    goto _twa_over;
×
6604
  }
6605

6606
  funcInputUpdate(pCtx);
7,025,685✔
6607
  SFuncInputRow row = {0};
7,025,685✔
6608
  bool          result = false;
7,025,685✔
6609
  if (pCtx->start.key != INT64_MIN && last->key == INT64_MIN) {
7,026,110✔
6610
    while (1) {
6611
      code = funcInputGetNextRow(pCtx, &row, &result);
5,154,275✔
6612
      if (TSDB_CODE_SUCCESS != code) {
5,154,275✔
6613
        return code;
×
6614
      }
6615
      if (!result) {
5,154,275✔
6616
        break;
728✔
6617
      }
6618
      if (row.isDataNull) {
5,153,547✔
6619
        continue;
728✔
6620
      }
6621

6622
      last->key = row.ts;
5,152,819✔
6623

6624
      GET_TYPED_DATA(last->val, double, pInputCol->info.type, row.pData, typeGetTypeModFromColInfo(&pInputCol->info));
5,152,819✔
6625

6626
      pInfo->dOutput += twa_get_area(pCtx->start, *last);
5,152,819✔
6627
      pInfo->win.skey = pCtx->start.key;
5,152,819✔
6628
      pInfo->numOfElems++;
5,152,819✔
6629
      break;
5,152,819✔
6630
    }
6631
  } else if (pInfo->p.key == INT64_MIN) {
1,872,563✔
6632
    while (1) {
6633
      code = funcInputGetNextRow(pCtx, &row, &result);
9,255,172✔
6634
      if (TSDB_CODE_SUCCESS != code) {
9,255,172✔
6635
        return code;
×
6636
      }
6637
      if (!result) {
9,255,172✔
6638
        break;
322,926✔
6639
      }
6640
      if (row.isDataNull) {
8,932,246✔
6641
        continue;
7,421,096✔
6642
      }
6643

6644
      last->key = row.ts;
1,511,150✔
6645

6646
      GET_TYPED_DATA(last->val, double, pInputCol->info.type, row.pData, typeGetTypeModFromColInfo(&pInputCol->info));
1,510,300✔
6647

6648
      pInfo->win.skey = last->key;
1,510,725✔
6649
      pInfo->numOfElems++;
1,511,150✔
6650
      break;
1,511,150✔
6651
    }
6652
  }
6653

6654
  SPoint1 st = {0};
7,026,110✔
6655

6656
  // calculate the value of
6657
  while (1) {
6658
    code = funcInputGetNextRow(pCtx, &row, &result);
177,483,507✔
6659
    if (TSDB_CODE_SUCCESS != code) {
177,612,282✔
6660
      return code;
×
6661
    }
6662
    if (!result) {
177,612,282✔
6663
      break;
7,026,110✔
6664
    }
6665
    if (row.isDataNull) {
170,586,172✔
6666
      continue;
53,550✔
6667
    }
6668
    pInfo->numOfElems++;
170,532,622✔
6669
    switch (pInputCol->info.type) {
170,537,297✔
6670
      case TSDB_DATA_TYPE_TINYINT: {
12,803,352✔
6671
        INIT_INTP_POINT(st, row.ts, *(int8_t*)row.pData);
12,803,352✔
6672
        break;
12,802,077✔
6673
      }
6674
      case TSDB_DATA_TYPE_SMALLINT: {
12,911,393✔
6675
        INIT_INTP_POINT(st, row.ts, *(int16_t*)row.pData);
12,911,393✔
6676
        break;
12,910,968✔
6677
      }
6678
      case TSDB_DATA_TYPE_INT: {
71,701,737✔
6679
        INIT_INTP_POINT(st, row.ts, *(int32_t*)row.pData);
71,701,737✔
6680
        break;
71,701,312✔
6681
      }
6682
      case TSDB_DATA_TYPE_BIGINT: {
14,086,513✔
6683
        INIT_INTP_POINT(st, row.ts, *(int64_t*)row.pData);
14,086,513✔
6684
        break;
14,086,513✔
6685
      }
6686
      case TSDB_DATA_TYPE_FLOAT: {
11,854,980✔
6687
        INIT_INTP_POINT(st, row.ts, *(float_t*)row.pData);
11,854,980✔
6688
        break;
11,854,555✔
6689
      }
6690
      case TSDB_DATA_TYPE_DOUBLE: {
13,514,288✔
6691
        INIT_INTP_POINT(st, row.ts, *(double*)row.pData);
13,514,288✔
6692
        break;
13,514,288✔
6693
      }
6694
      case TSDB_DATA_TYPE_UTINYINT: {
8,598,560✔
6695
        INIT_INTP_POINT(st, row.ts, *(uint8_t*)row.pData);
8,598,560✔
6696
        break;
8,598,560✔
6697
      }
6698
      case TSDB_DATA_TYPE_USMALLINT: {
8,606,635✔
6699
        INIT_INTP_POINT(st, row.ts, *(uint16_t*)row.pData);
8,606,635✔
6700
        break;
8,606,635✔
6701
      }
6702
      case TSDB_DATA_TYPE_UINT: {
8,673,407✔
6703
        INIT_INTP_POINT(st, row.ts, *(uint32_t*)row.pData);
8,673,407✔
6704
        break;
8,672,982✔
6705
      }
6706
      case TSDB_DATA_TYPE_UBIGINT: {
7,782,607✔
6707
        INIT_INTP_POINT(st, row.ts, *(uint64_t*)row.pData);
7,782,607✔
6708
        break;
7,781,757✔
6709
      }
6710
      default: {
×
6711
        return TSDB_CODE_FUNC_FUNTION_PARA_TYPE;
×
6712
      }
6713
    }
6714
    if (pInfo->p.key == st.key) {
170,529,647✔
6715
      return TSDB_CODE_FUNC_DUP_TIMESTAMP;
×
6716
    }
6717

6718
    pInfo->dOutput += twa_get_area(pInfo->p, st);
170,527,097✔
6719
    pInfo->p = st;
170,413,197✔
6720
  }
6721

6722
  // the last interpolated time window value
6723
  if (pCtx->end.key != INT64_MIN) {
7,026,110✔
6724
    pInfo->dOutput += twa_get_area(pInfo->p, pCtx->end);
5,155,698✔
6725
    pInfo->p = pCtx->end;
5,155,698✔
6726
    pInfo->numOfElems += 1;
5,155,698✔
6727
  }
6728

6729
  pInfo->win.ekey = pInfo->p.key;
7,026,110✔
6730

6731
_twa_over:
7,024,835✔
6732
  SET_VAL(pResInfo, 1, 1);
7,025,685✔
6733
  return TSDB_CODE_SUCCESS;
7,025,260✔
6734
}
6735

6736
/*
6737
 * To copy the input to interResBuf to avoid the input buffer space be over writen
6738
 * by next input data. The TWA function only applies to each table, so no merge procedure
6739
 * is required, we simply copy to the resut ot interResBuffer.
6740
 */
6741
// void twa_function_copy(SQLFunctionCtx *pCtx) {
6742
//   SResultRowEntryInfo *pResInfo = GET_RES_INFO(pCtx);
6743
//
6744
//   memcpy(GET_ROWCELL_INTERBUF(pResInfo), pCtx->pInput, (size_t)pCtx->inputBytes);
6745
//   pResInfo->hasResult = ((STwaInfo *)pCtx->pInput)->hasResult;
6746
// }
6747

6748
int32_t twaFinalize(struct SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
6,978,443✔
6749
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
6,978,443✔
6750

6751
  STwaInfo* pInfo = (STwaInfo*)GET_ROWCELL_INTERBUF(pResInfo);
6,978,443✔
6752
  if (pInfo->numOfElems == 0) {
6,978,443✔
6753
    pResInfo->numOfRes = 0;
313,746✔
6754
  } else {
6755
    if (pInfo->win.ekey == pInfo->win.skey) {
6,664,697✔
6756
      pInfo->dTwaRes = pInfo->p.val;
680,510✔
6757
    } else if (pInfo->win.ekey == INT64_MAX || pInfo->win.skey == INT64_MIN) {  // no data in timewindow
5,984,187✔
6758
      pInfo->dTwaRes = 0;
728✔
6759
    } else {
6760
      pInfo->dTwaRes = pInfo->dOutput / (pInfo->win.ekey - pInfo->win.skey);
5,983,459✔
6761
    }
6762

6763
    pResInfo->numOfRes = 1;
6,664,697✔
6764
  }
6765

6766
  return functionFinalize(pCtx, pBlock);
6,978,443✔
6767
}
6768

6769
int32_t blockDistSetup(SqlFunctionCtx* pCtx, SResultRowEntryInfo* pResultInfo) {
2,830✔
6770
  if (pResultInfo->initialized) {
2,830✔
6771
    return TSDB_CODE_SUCCESS;
×
6772
  }
6773
  if (TSDB_CODE_SUCCESS != functionSetup(pCtx, pResultInfo)) {
2,830✔
6774
    return TSDB_CODE_FUNC_SETUP_ERROR;
×
6775
  }
6776

6777
  STableBlockDistInfo* pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
2,830✔
6778
  pInfo->minRows = INT32_MAX;
2,830✔
6779
  return TSDB_CODE_SUCCESS;
2,830✔
6780
}
6781

6782
int32_t blockDistFunction(SqlFunctionCtx* pCtx) {
5,399✔
6783
  const int32_t BLOCK_DIST_RESULT_ROWS = 25;
5,399✔
6784

6785
  SInputColumnInfoData* pInput = &pCtx->input;
5,399✔
6786
  SColumnInfoData*      pInputCol = pInput->pData[0];
5,399✔
6787
  SResultRowEntryInfo*  pResInfo = GET_RES_INFO(pCtx);
5,399✔
6788
  STableBlockDistInfo*  pDistInfo = GET_ROWCELL_INTERBUF(pResInfo);
5,399✔
6789

6790
  STableBlockDistInfo p1 = {0};
5,399✔
6791
  if (tDeserializeBlockDistInfo(varDataVal(pInputCol->pData), varDataLen(pInputCol->pData), &p1) < 0) {
5,399✔
6792
    qError("failed to deserialize block dist info");
×
6793
    return TSDB_CODE_FAILED;
×
6794
  }
6795

6796
  pDistInfo->numOfBlocks += p1.numOfBlocks;
5,399✔
6797
  pDistInfo->numOfTables += p1.numOfTables;
5,399✔
6798
  pDistInfo->numOfInmemRows += p1.numOfInmemRows;
5,399✔
6799
  pDistInfo->numOfSttRows += p1.numOfSttRows;
5,399✔
6800
  pDistInfo->totalSize += p1.totalSize;
5,399✔
6801
  pDistInfo->totalRows += p1.totalRows;
5,399✔
6802
  pDistInfo->numOfFiles += p1.numOfFiles;
5,399✔
6803

6804
  pDistInfo->defMinRows = p1.defMinRows;
5,399✔
6805
  pDistInfo->defMaxRows = p1.defMaxRows;
5,399✔
6806
  pDistInfo->rowSize = p1.rowSize;
5,399✔
6807

6808
  if (pDistInfo->minRows > p1.minRows) {
5,399✔
6809
    pDistInfo->minRows = p1.minRows;
1,255✔
6810
  }
6811
  if (pDistInfo->maxRows < p1.maxRows) {
5,399✔
6812
    pDistInfo->maxRows = p1.maxRows;
1,255✔
6813
  }
6814
  pDistInfo->numOfVgroups += (p1.numOfTables != 0 ? 1 : 0);
5,399✔
6815
  for (int32_t i = 0; i < tListLen(pDistInfo->blockRowsHisto); ++i) {
113,379✔
6816
    pDistInfo->blockRowsHisto[i] += p1.blockRowsHisto[i];
107,980✔
6817
  }
6818

6819
  pResInfo->numOfRes = BLOCK_DIST_RESULT_ROWS;  // default output rows
5,399✔
6820
  return TSDB_CODE_SUCCESS;
5,399✔
6821
}
6822

6823
int32_t tSerializeBlockDistInfo(void* buf, int32_t bufLen, const STableBlockDistInfo* pInfo) {
10,765✔
6824
  SEncoder encoder = {0};
10,765✔
6825
  int32_t  code = 0;
10,798✔
6826
  int32_t  lino;
6827
  int32_t  tlen;
6828
  tEncoderInit(&encoder, buf, bufLen);
10,798✔
6829

6830
  TAOS_CHECK_EXIT(tStartEncode(&encoder));
10,798✔
6831
  TAOS_CHECK_EXIT(tEncodeU32(&encoder, pInfo->rowSize));
21,563✔
6832

6833
  TAOS_CHECK_EXIT(tEncodeU16(&encoder, pInfo->numOfFiles));
21,530✔
6834
  TAOS_CHECK_EXIT(tEncodeU32(&encoder, pInfo->numOfBlocks));
21,530✔
6835
  TAOS_CHECK_EXIT(tEncodeU32(&encoder, pInfo->numOfTables));
21,530✔
6836

6837
  TAOS_CHECK_EXIT(tEncodeU64(&encoder, pInfo->totalSize));
21,530✔
6838
  TAOS_CHECK_EXIT(tEncodeU64(&encoder, pInfo->totalRows));
21,530✔
6839
  TAOS_CHECK_EXIT(tEncodeI32(&encoder, pInfo->maxRows));
21,530✔
6840
  TAOS_CHECK_EXIT(tEncodeI32(&encoder, pInfo->minRows));
21,530✔
6841
  TAOS_CHECK_EXIT(tEncodeI32(&encoder, pInfo->defMaxRows));
21,530✔
6842
  TAOS_CHECK_EXIT(tEncodeI32(&encoder, pInfo->defMinRows));
21,530✔
6843
  TAOS_CHECK_EXIT(tEncodeU32(&encoder, pInfo->numOfInmemRows));
21,530✔
6844
  TAOS_CHECK_EXIT(tEncodeU32(&encoder, pInfo->numOfSttRows));
21,563✔
6845
  TAOS_CHECK_EXIT(tEncodeU32(&encoder, pInfo->numOfVgroups));
21,596✔
6846

6847
  for (int32_t i = 0; i < tListLen(pInfo->blockRowsHisto); ++i) {
226,725✔
6848
    TAOS_CHECK_EXIT(tEncodeI32(&encoder, pInfo->blockRowsHisto[i]));
431,854✔
6849
  }
6850

6851
  tEndEncode(&encoder);
10,798✔
6852

6853
_exit:
10,765✔
6854
  if (code) {
10,765✔
6855
    tlen = code;
×
6856
  } else {
6857
    tlen = encoder.pos;
10,765✔
6858
  }
6859
  tEncoderClear(&encoder);
10,765✔
6860
  return tlen;
10,798✔
6861
}
6862

6863
int32_t tDeserializeBlockDistInfo(void* buf, int32_t bufLen, STableBlockDistInfo* pInfo) {
5,399✔
6864
  SDecoder decoder = {0};
5,399✔
6865
  int32_t  code = 0;
5,399✔
6866
  int32_t  lino;
6867
  tDecoderInit(&decoder, buf, bufLen);
5,399✔
6868

6869
  TAOS_CHECK_EXIT(tStartDecode(&decoder));
5,399✔
6870
  TAOS_CHECK_EXIT(tDecodeU32(&decoder, &pInfo->rowSize));
10,798✔
6871

6872
  TAOS_CHECK_EXIT(tDecodeU16(&decoder, &pInfo->numOfFiles));
10,798✔
6873
  TAOS_CHECK_EXIT(tDecodeU32(&decoder, &pInfo->numOfBlocks));
10,798✔
6874
  TAOS_CHECK_EXIT(tDecodeU32(&decoder, &pInfo->numOfTables));
10,798✔
6875

6876
  TAOS_CHECK_EXIT(tDecodeU64(&decoder, &pInfo->totalSize));
10,798✔
6877
  TAOS_CHECK_EXIT(tDecodeU64(&decoder, &pInfo->totalRows));
10,798✔
6878
  TAOS_CHECK_EXIT(tDecodeI32(&decoder, &pInfo->maxRows));
10,798✔
6879
  TAOS_CHECK_EXIT(tDecodeI32(&decoder, &pInfo->minRows));
10,798✔
6880
  TAOS_CHECK_EXIT(tDecodeI32(&decoder, &pInfo->defMaxRows));
10,798✔
6881
  TAOS_CHECK_EXIT(tDecodeI32(&decoder, &pInfo->defMinRows));
10,798✔
6882
  TAOS_CHECK_EXIT(tDecodeU32(&decoder, &pInfo->numOfInmemRows));
10,798✔
6883
  TAOS_CHECK_EXIT(tDecodeU32(&decoder, &pInfo->numOfSttRows));
10,798✔
6884
  TAOS_CHECK_EXIT(tDecodeU32(&decoder, &pInfo->numOfVgroups));
10,798✔
6885

6886
  for (int32_t i = 0; i < tListLen(pInfo->blockRowsHisto); ++i) {
113,379✔
6887
    TAOS_CHECK_EXIT(tDecodeI32(&decoder, &pInfo->blockRowsHisto[i]));
215,960✔
6888
  }
6889

6890
_exit:
5,399✔
6891
  tDecoderClear(&decoder);
5,399✔
6892
  return code;
5,399✔
6893
}
6894

6895
int32_t blockDistFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
2,830✔
6896
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
2,830✔
6897
  STableBlockDistInfo* pData = GET_ROWCELL_INTERBUF(pResInfo);
2,830✔
6898

6899
  SColumnInfoData* pColInfo = taosArrayGet(pBlock->pDataBlock, 0);
2,830✔
6900
  if (NULL == pColInfo) {
2,830✔
6901
    return TSDB_CODE_OUT_OF_RANGE;
×
6902
  }
6903

6904
  if (pData->totalRows == 0) {
2,830✔
6905
    pData->minRows = 0;
1,575✔
6906
  }
6907

6908
  int32_t row = 0;
2,830✔
6909
  char    st[256] = {0};
2,830✔
6910
  double  averageSize = 0;
2,830✔
6911
  if (pData->numOfBlocks != 0) {
2,830✔
6912
    averageSize = ((double)pData->totalSize) / pData->numOfBlocks;
1,255✔
6913
  }
6914
  uint64_t totalRawSize = pData->totalRows * pData->rowSize;
2,830✔
6915
  double   compRatio = 0;
2,830✔
6916
  if (totalRawSize != 0) {
2,830✔
6917
    compRatio = pData->totalSize * 100 / (double)totalRawSize;
1,255✔
6918
  }
6919

6920
  int32_t len = tsnprintf(varDataVal(st), sizeof(st) - VARSTR_HEADER_SIZE,
2,830✔
6921
                          "Total_Blocks=[%d] Total_Size=[%.2f KiB] Average_size=[%.2f KiB] Compression_Ratio=[%.2f %c]",
6922
                          pData->numOfBlocks, pData->totalSize / 1024.0, averageSize / 1024.0, compRatio, '%');
2,830✔
6923

6924
  varDataSetLen(st, len);
2,830✔
6925
  int32_t code = colDataSetVal(pColInfo, row++, st, false);
2,830✔
6926
  if (TSDB_CODE_SUCCESS != code) {
2,830✔
6927
    return code;
×
6928
  }
6929

6930
  int64_t avgRows = 0;
2,830✔
6931
  if (pData->numOfBlocks > 0) {
2,830✔
6932
    avgRows = pData->totalRows / pData->numOfBlocks;
1,255✔
6933
  }
6934

6935
  len = tsnprintf(varDataVal(st), sizeof(st) - VARSTR_HEADER_SIZE,
2,830✔
6936
                  "Block_Rows=[%" PRId64 "] MinRows=[%d] MaxRows=[%d] AvgRows=[%" PRId64 "]", pData->totalRows,
6937
                  pData->minRows, pData->maxRows, avgRows);
6938
  varDataSetLen(st, len);
2,830✔
6939
  code = colDataSetVal(pColInfo, row++, st, false);
2,830✔
6940
  if (TSDB_CODE_SUCCESS != code) {
2,830✔
6941
    return code;
×
6942
  }
6943

6944
  len = tsnprintf(varDataVal(st), sizeof(st) - VARSTR_HEADER_SIZE, "Inmem_Rows=[%u] Stt_Rows=[%u] ",
2,830✔
6945
                  pData->numOfInmemRows, pData->numOfSttRows);
6946
  varDataSetLen(st, len);
2,830✔
6947
  code = colDataSetVal(pColInfo, row++, st, false);
2,830✔
6948
  if (TSDB_CODE_SUCCESS != code) {
2,830✔
6949
    return code;
×
6950
  }
6951

6952
  len = tsnprintf(varDataVal(st), sizeof(st) - VARSTR_HEADER_SIZE,
5,660✔
6953
                  "Total_Tables=[%d] Total_Filesets=[%d] Total_Vgroups=[%d]", pData->numOfTables, pData->numOfFiles,
2,830✔
6954
                  pData->numOfVgroups);
6955

6956
  varDataSetLen(st, len);
2,830✔
6957
  code = colDataSetVal(pColInfo, row++, st, false);
2,830✔
6958
  if (TSDB_CODE_SUCCESS != code) {
2,830✔
6959
    return code;
×
6960
  }
6961

6962
  len = tsnprintf(varDataVal(st), sizeof(st) - VARSTR_HEADER_SIZE,
2,830✔
6963
                  "--------------------------------------------------------------------------------");
6964
  varDataSetLen(st, len);
2,830✔
6965
  code = colDataSetVal(pColInfo, row++, st, false);
2,830✔
6966
  if (TSDB_CODE_SUCCESS != code) {
2,830✔
6967
    return code;
×
6968
  }
6969

6970
  int32_t maxVal = 0;
2,830✔
6971
  int32_t minVal = INT32_MAX;
2,830✔
6972
  for (int32_t i = 0; i < tListLen(pData->blockRowsHisto); ++i) {
59,430✔
6973
    if (maxVal < pData->blockRowsHisto[i]) {
56,600✔
6974
      maxVal = pData->blockRowsHisto[i];
1,799✔
6975
    }
6976

6977
    if (minVal > pData->blockRowsHisto[i]) {
56,600✔
6978
      minVal = pData->blockRowsHisto[i];
3,541✔
6979
    }
6980
  }
6981

6982
  // maximum number of step is 80
6983
  double factor = pData->numOfBlocks / 80.0;
2,830✔
6984

6985
  int32_t numOfBuckets = sizeof(pData->blockRowsHisto) / sizeof(pData->blockRowsHisto[0]);
2,830✔
6986
  int32_t bucketRange = ceil(((double)(pData->defMaxRows - pData->defMinRows)) / numOfBuckets);
2,830✔
6987

6988
  for (int32_t i = 0; i < tListLen(pData->blockRowsHisto); ++i) {
59,430✔
6989
    len =
56,600✔
6990
        tsnprintf(varDataVal(st), sizeof(st) - VARSTR_HEADER_SIZE, "%04d |", pData->defMinRows + bucketRange * (i + 1));
56,600✔
6991

6992
    int32_t num = 0;
56,600✔
6993
    if (pData->blockRowsHisto[i] > 0) {
56,600✔
6994
      num = (pData->blockRowsHisto[i]) / factor;
2,887✔
6995
    }
6996

6997
    for (int32_t j = 0; j < num; ++j) {
156,456✔
6998
      int32_t x = tsnprintf(varDataVal(st) + len, sizeof(st) - VARSTR_HEADER_SIZE - len, "%c", '|');
99,856✔
6999
      len += x;
99,856✔
7000
    }
7001

7002
    if (pData->blockRowsHisto[i] > 0) {
56,600✔
7003
      double v = pData->blockRowsHisto[i] * 100.0 / pData->numOfBlocks;
2,887✔
7004
      len += tsnprintf(varDataVal(st) + len, sizeof(st) - VARSTR_HEADER_SIZE - len, "  %d (%.2f%c)",
2,887✔
7005
                       pData->blockRowsHisto[i], v, '%');
7006
    }
7007

7008
    varDataSetLen(st, len);
56,600✔
7009
    code = colDataSetVal(pColInfo, row++, st, false);
56,600✔
7010
    if (TSDB_CODE_SUCCESS != code) {
56,600✔
7011
      return code;
×
7012
    }
7013
  }
7014

7015
  return TSDB_CODE_SUCCESS;
2,830✔
7016
}
7017
int32_t blockDBUsageSetup(SqlFunctionCtx* pCtx, SResultRowEntryInfo* pResultInfo) {
351✔
7018
  if (pResultInfo->initialized) {
351✔
7019
    return TSDB_CODE_SUCCESS;
×
7020
  }
7021
  if (TSDB_CODE_SUCCESS != functionSetup(pCtx, pResultInfo)) {
351✔
7022
    return TSDB_CODE_FUNC_SETUP_ERROR;
×
7023
  }
7024

7025
  SDBBlockUsageInfo* pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
351✔
7026
  return TSDB_CODE_SUCCESS;
351✔
7027
}
7028
int32_t blockDBUsageFunction(SqlFunctionCtx* pCtx) {
702✔
7029
  const int32_t BLOCK_DISK_USAGE_RESULT_ROWS = 2;
702✔
7030

7031
  SInputColumnInfoData* pInput = &pCtx->input;
702✔
7032
  SColumnInfoData*      pInputCol = pInput->pData[0];
702✔
7033
  SResultRowEntryInfo*  pResInfo = GET_RES_INFO(pCtx);
702✔
7034
  SDBBlockUsageInfo*    pDistInfo = GET_ROWCELL_INTERBUF(pResInfo);
702✔
7035

7036
  SDBBlockUsageInfo p1 = {0};
702✔
7037
  if (tDeserializeBlockDbUsage(varDataVal(pInputCol->pData), varDataLen(pInputCol->pData), &p1) < 0) {
702✔
7038
    qError("failed to deserialize block dist info");
×
7039
    return TSDB_CODE_FAILED;
×
7040
  }
7041

7042
  pDistInfo->dataInDiskSize += p1.dataInDiskSize;
702✔
7043
  pDistInfo->walInDiskSize += p1.walInDiskSize;
702✔
7044
  pDistInfo->rawDataSize += p1.rawDataSize;
702✔
7045
  pResInfo->numOfRes = BLOCK_DISK_USAGE_RESULT_ROWS;  // default output rows
702✔
7046
  return TSDB_CODE_SUCCESS;
702✔
7047
}
7048

7049
int32_t tSerializeBlockDbUsage(void* buf, int32_t bufLen, const SDBBlockUsageInfo* pInfo) {
1,404✔
7050
  SEncoder encoder = {0};
1,404✔
7051
  int32_t  code = 0;
1,404✔
7052
  int32_t  lino;
7053
  int32_t  tlen;
7054
  tEncoderInit(&encoder, buf, bufLen);
1,404✔
7055

7056
  TAOS_CHECK_EXIT(tStartEncode(&encoder));
1,404✔
7057

7058
  TAOS_CHECK_EXIT(tEncodeU64(&encoder, pInfo->dataInDiskSize));
2,808✔
7059
  TAOS_CHECK_EXIT(tEncodeU64(&encoder, pInfo->walInDiskSize));
2,808✔
7060
  TAOS_CHECK_EXIT(tEncodeU64(&encoder, pInfo->rawDataSize));
2,808✔
7061

7062
  tEndEncode(&encoder);
1,404✔
7063

7064
_exit:
1,404✔
7065
  if (code) {
1,404✔
7066
    tlen = code;
×
7067
  } else {
7068
    tlen = encoder.pos;
1,404✔
7069
  }
7070
  tEncoderClear(&encoder);
1,404✔
7071
  return tlen;
1,404✔
7072
}
7073
int32_t tDeserializeBlockDbUsage(void* buf, int32_t bufLen, SDBBlockUsageInfo* pInfo) {
702✔
7074
  SDecoder decoder = {0};
702✔
7075
  int32_t  code = 0;
702✔
7076
  int32_t  lino;
7077
  tDecoderInit(&decoder, buf, bufLen);
702✔
7078

7079
  TAOS_CHECK_EXIT(tStartDecode(&decoder));
702✔
7080
  TAOS_CHECK_EXIT(tDecodeU64(&decoder, &pInfo->dataInDiskSize));
1,404✔
7081
  TAOS_CHECK_EXIT(tDecodeU64(&decoder, &pInfo->walInDiskSize));
1,404✔
7082
  TAOS_CHECK_EXIT(tDecodeU64(&decoder, &pInfo->rawDataSize));
1,404✔
7083

7084
_exit:
702✔
7085
  tDecoderClear(&decoder);
702✔
7086
  return code;
702✔
7087
}
7088
int32_t blockDBUsageFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
351✔
7089
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
351✔
7090
  SDBBlockUsageInfo*   pData = GET_ROWCELL_INTERBUF(pResInfo);
351✔
7091

7092
  SColumnInfoData* pColInfo = taosArrayGet(pBlock->pDataBlock, 0);
351✔
7093
  if (NULL == pColInfo) {
351✔
7094
    return TSDB_CODE_OUT_OF_RANGE;
×
7095
  }
7096
  int32_t len = 0;
351✔
7097
  int32_t row = 0;
351✔
7098
  char    st[256] = {0};
351✔
7099

7100
  uint64_t totalDiskSize = pData->dataInDiskSize;
351✔
7101
  uint64_t rawDataSize = pData->rawDataSize;
351✔
7102
  double   compressRatio = 0;
351✔
7103
  if (rawDataSize != 0) {
351✔
UNCOV
7104
    compressRatio = totalDiskSize * 100 / (double)rawDataSize;
×
UNCOV
7105
    len = tsnprintf(varDataVal(st), sizeof(st) - VARSTR_HEADER_SIZE, "Compress_ratio=[%.2f%]", compressRatio);
×
7106
  } else {
7107
    len = tsnprintf(varDataVal(st), sizeof(st) - VARSTR_HEADER_SIZE, "Compress_ratio=[NULL]");
351✔
7108
  }
7109

7110
  varDataSetLen(st, len);
351✔
7111
  int32_t code = colDataSetVal(pColInfo, row++, st, false);
351✔
7112
  if (TSDB_CODE_SUCCESS != code) {
351✔
7113
    return code;
×
7114
  }
7115

7116
  len =
351✔
7117
      tsnprintf(varDataVal(st), sizeof(st) - VARSTR_HEADER_SIZE, "Disk_occupied=[%" PRId64 "k]", pData->dataInDiskSize);
351✔
7118
  varDataSetLen(st, len);
351✔
7119
  code = colDataSetVal(pColInfo, row++, st, false);
351✔
7120
  if (TSDB_CODE_SUCCESS != code) {
351✔
7121
    return code;
×
7122
  }
7123
  return code;
351✔
7124
}
7125

7126
bool getDerivativeFuncEnv(struct SFunctionNode* pFunc, SFuncExecEnv* pEnv) {
199,471✔
7127
  pEnv->calcMemSize = sizeof(SDerivInfo);
199,471✔
7128
  return true;
199,471✔
7129
}
7130

7131
int32_t derivativeFuncSetup(SqlFunctionCtx* pCtx, SResultRowEntryInfo* pResInfo) {
449,038✔
7132
  if (pResInfo->initialized) {
449,038✔
7133
    return TSDB_CODE_SUCCESS;
221,961✔
7134
  }
7135
  if (TSDB_CODE_SUCCESS != functionSetup(pCtx, pResInfo)) {
227,077✔
7136
    return TSDB_CODE_FUNC_SETUP_ERROR;
×
7137
  }
7138

7139
  SDerivInfo* pDerivInfo = GET_ROWCELL_INTERBUF(pResInfo);
227,077✔
7140

7141
  pDerivInfo->ignoreNegative = pCtx->param[2].param.i;
227,077✔
7142
  pDerivInfo->prevTs = -1;
227,077✔
7143
  pDerivInfo->tsWindow = pCtx->param[1].param.i;
227,077✔
7144
  pDerivInfo->valueSet = false;
227,077✔
7145
  return TSDB_CODE_SUCCESS;
227,077✔
7146
}
7147

7148
int32_t derivativeFunction(SqlFunctionCtx* pCtx) { return TSDB_CODE_SUCCESS; }
249,567✔
7149

7150
static int32_t DoDerivativeFunction(SqlFunctionCtx* pCtx) {
249,567✔
7151
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
249,567✔
7152
  SDerivInfo*          pDerivInfo = GET_ROWCELL_INTERBUF(pResInfo);
249,567✔
7153

7154
  SInputColumnInfoData* pInput = &pCtx->input;
249,567✔
7155
  SColumnInfoData*      pInputCol = pInput->pData[0];
249,567✔
7156

7157
  int32_t          numOfElems = 0;
249,567✔
7158
  SColumnInfoData* pOutput = (SColumnInfoData*)pCtx->pOutput;
249,567✔
7159
  SColumnInfoData* pTsOutput = pCtx->pTsOutput;
249,567✔
7160
  int32_t          code = TSDB_CODE_SUCCESS;
249,567✔
7161

7162
  funcInputUpdate(pCtx);
249,567✔
7163

7164
  double v = 0;
249,567✔
7165
  if (pCtx->order == TSDB_ORDER_ASC) {
249,567✔
7166
    SFuncInputRow row = {0};
244,467✔
7167
    bool          result = false;
244,467✔
7168
    while (1) {
119,472,212✔
7169
      code = funcInputGetNextRow(pCtx, &row, &result);
119,716,679✔
7170
      if (TSDB_CODE_SUCCESS != code) {
119,716,679✔
7171
        return code;
×
7172
      }
7173
      if (!result) {
119,716,679✔
7174
        break;
244,467✔
7175
      }
7176
      if (row.isDataNull) {
119,472,212✔
7177
        continue;
2,056,330✔
7178
      }
7179

7180
      char* d = row.pData;
117,415,882✔
7181
      GET_TYPED_DATA(v, double, pInputCol->info.type, d, typeGetTypeModFromColInfo(&pInputCol->info));
117,415,882✔
7182

7183
      int32_t pos = pCtx->offset + numOfElems;
117,415,882✔
7184
      if (!pDerivInfo->valueSet) {  // initial value is not set yet
117,415,882✔
7185
        pDerivInfo->valueSet = true;
199,763✔
7186
      } else {
7187
        if (row.ts == pDerivInfo->prevTs) {
117,216,119✔
7188
          return TSDB_CODE_FUNC_DUP_TIMESTAMP;
×
7189
        }
7190
        double r = ((v - pDerivInfo->prevValue) * pDerivInfo->tsWindow) / (row.ts - pDerivInfo->prevTs);
117,216,119✔
7191
        if (pDerivInfo->ignoreNegative && r < 0) {
117,216,119✔
7192
        } else {
7193
          if (isinf(r) || isnan(r)) {
106,565,295✔
7194
            colDataSetNULL(pOutput, pos);
×
7195
          } else {
7196
            code = colDataSetVal(pOutput, pos, (const char*)&r, false);
106,565,295✔
7197
            if (code != TSDB_CODE_SUCCESS) {
106,565,295✔
7198
              return code;
×
7199
            }
7200
          }
7201

7202
          if (pTsOutput != NULL) {
106,565,295✔
7203
            colDataSetInt64(pTsOutput, pos, &row.ts);
×
7204
          }
7205

7206
          // handle selectivity
7207
          if (pCtx->subsidiaries.num > 0) {
106,565,295✔
7208
            code = appendSelectivityCols(pCtx, row.block, row.rowIndex, pos);
1,898,181✔
7209
            if (code != TSDB_CODE_SUCCESS) {
1,898,181✔
7210
              return code;
×
7211
            }
7212
          }
7213

7214
          numOfElems++;
106,565,295✔
7215
        }
7216
      }
7217

7218
      pDerivInfo->prevValue = v;
117,415,882✔
7219
      pDerivInfo->prevTs = row.ts;
117,415,882✔
7220
    }
7221
  } else {
7222
    SFuncInputRow row = {0};
5,100✔
7223
    bool          result = false;
5,100✔
7224
    while (1) {
19,380✔
7225
      code = funcInputGetNextRow(pCtx, &row, &result);
24,480✔
7226
      if (TSDB_CODE_SUCCESS != code) {
24,480✔
7227
        return code;
×
7228
      }
7229
      if (!result) {
24,480✔
7230
        break;
5,100✔
7231
      }
7232
      if (row.isDataNull) {
19,380✔
7233
        continue;
4,080✔
7234
      }
7235

7236
      char* d = row.pData;
15,300✔
7237
      GET_TYPED_DATA(v, double, pInputCol->info.type, d, typeGetTypeModFromColInfo(&pInputCol->info));
15,300✔
7238

7239
      int32_t pos = pCtx->offset + numOfElems;
15,300✔
7240
      if (!pDerivInfo->valueSet) {  // initial value is not set yet
15,300✔
7241
        pDerivInfo->valueSet = true;
3,060✔
7242
      } else {
7243
        if (row.ts == pDerivInfo->prevTs) {
12,240✔
7244
          return TSDB_CODE_FUNC_DUP_TIMESTAMP;
×
7245
        }
7246
        double r = ((pDerivInfo->prevValue - v) * pDerivInfo->tsWindow) / (pDerivInfo->prevTs - row.ts);
12,240✔
7247
        if (pDerivInfo->ignoreNegative && r < 0) {
12,240✔
7248
        } else {
7249
          if (isinf(r) || isnan(r)) {
12,240✔
7250
            colDataSetNULL(pOutput, pos);
×
7251
          } else {
7252
            code = colDataSetVal(pOutput, pos, (const char*)&r, false);
12,240✔
7253
            if (code != TSDB_CODE_SUCCESS) {
12,240✔
7254
              return code;
×
7255
            }
7256
          }
7257

7258
          if (pTsOutput != NULL) {
12,240✔
7259
            colDataSetInt64(pTsOutput, pos, &pDerivInfo->prevTs);
×
7260
          }
7261

7262
          // handle selectivity
7263
          if (pCtx->subsidiaries.num > 0) {
12,240✔
7264
            code = appendSelectivityCols(pCtx, row.block, row.rowIndex, pos);
×
7265
            if (code != TSDB_CODE_SUCCESS) {
×
7266
              return code;
×
7267
            }
7268
          }
7269
          numOfElems++;
12,240✔
7270
        }
7271
      }
7272

7273
      pDerivInfo->prevValue = v;
15,300✔
7274
      pDerivInfo->prevTs = row.ts;
15,300✔
7275
    }
7276
  }
7277

7278
  pResInfo->numOfRes = numOfElems;
249,567✔
7279

7280
  return TSDB_CODE_SUCCESS;
249,567✔
7281
}
7282

7283
int32_t derivativeFunctionByRow(SArray* pCtxArray) {
249,567✔
7284
  for (int32_t i = 0; i < taosArrayGetSize(pCtxArray); ++i) {
499,134✔
7285
    SqlFunctionCtx* pCtx = *(SqlFunctionCtx**)taosArrayGet(pCtxArray, i);
249,567✔
7286
    int32_t         code = DoDerivativeFunction(pCtx);
249,567✔
7287
    if (code != TSDB_CODE_SUCCESS) {
249,567✔
7288
      return code;
×
7289
    }
7290
  }
7291
  return TSDB_CODE_SUCCESS;
249,567✔
7292
}
7293

7294
int32_t getIrateInfoSize(int32_t pkBytes) { return (int32_t)sizeof(SRateInfo) + 2 * pkBytes; }
247,068✔
7295

7296
bool getIrateFuncEnv(struct SFunctionNode* pFunc, SFuncExecEnv* pEnv) {
206,405✔
7297
  int32_t pkBytes = (pFunc->hasPk) ? pFunc->pkBytes : 0;
206,405✔
7298
  pEnv->calcMemSize = getIrateInfoSize(pkBytes);
205,895✔
7299
  return true;
206,405✔
7300
}
7301

7302
int32_t irateFuncSetup(SqlFunctionCtx* pCtx, SResultRowEntryInfo* pResInfo) {
2,119,231✔
7303
  if (pResInfo->initialized) {
2,119,231✔
7304
    return TSDB_CODE_SUCCESS;
×
7305
  }
7306
  if (TSDB_CODE_SUCCESS != functionSetup(pCtx, pResInfo)) {
2,119,231✔
7307
    return TSDB_CODE_FUNC_SETUP_ERROR;
×
7308
  }
7309

7310
  SRateInfo* pInfo = GET_ROWCELL_INTERBUF(pResInfo);
2,119,231✔
7311

7312
  pInfo->firstKey = INT64_MIN;
2,119,231✔
7313
  pInfo->lastKey = INT64_MIN;
2,119,231✔
7314
  pInfo->firstValue = (double)INT64_MIN;
2,119,231✔
7315
  pInfo->lastValue = (double)INT64_MIN;
2,119,231✔
7316

7317
  pInfo->hasResult = 0;
2,119,231✔
7318
  return TSDB_CODE_SUCCESS;
2,119,231✔
7319
}
7320

7321
static void doSaveRateInfo(SRateInfo* pRateInfo, bool isFirst, int64_t ts, char* pk, double v) {
289,287,761✔
7322
  if (isFirst) {
289,287,761✔
7323
    pRateInfo->firstValue = v;
143,984,945✔
7324
    pRateInfo->firstKey = ts;
143,984,945✔
7325
    if (pRateInfo->firstPk) {
143,984,945✔
7326
      int32_t pkBytes;
7327
      if (IS_VAR_DATA_TYPE(pRateInfo->pkType)) {
23,870✔
7328
        pkBytes = calcStrBytesByType(pRateInfo->pkType, pk);
5,456✔
7329
      } else {
7330
        pkBytes = pRateInfo->pkBytes;
18,414✔
7331
      }
7332
      (void)memcpy(pRateInfo->firstPk, pk, pkBytes);
23,870✔
7333
    }
7334
  } else {
7335
    pRateInfo->lastValue = v;
145,302,816✔
7336
    pRateInfo->lastKey = ts;
145,302,816✔
7337
    if (pRateInfo->lastPk) {
145,302,816✔
7338
      int32_t pkBytes;
7339
      if (IS_VAR_DATA_TYPE(pRateInfo->pkType)) {
35,464✔
7340
        pkBytes = calcStrBytesByType(pRateInfo->pkType, pk);
8,184✔
7341
      } else {
7342
        pkBytes = pRateInfo->pkBytes;
27,280✔
7343
      }
7344
      (void)memcpy(pRateInfo->lastPk, pk, pkBytes);
35,464✔
7345
    }
7346
  }
7347
}
289,287,761✔
7348

7349
static void initializeRateInfo(SqlFunctionCtx* pCtx, SRateInfo* pRateInfo, bool isMerge) {
2,258,876✔
7350
  if (pCtx->hasPrimaryKey) {
2,258,876✔
7351
    if (!isMerge) {
12,958✔
7352
      pRateInfo->pkType = pCtx->input.pPrimaryKey->info.type;
11,594✔
7353
      pRateInfo->pkBytes = pCtx->input.pPrimaryKey->info.bytes;
11,594✔
7354
      pRateInfo->firstPk = pRateInfo->pkData;
11,594✔
7355
      pRateInfo->lastPk = pRateInfo->pkData + pRateInfo->pkBytes;
11,594✔
7356
    } else {
7357
      pRateInfo->firstPk = pRateInfo->pkData;
1,364✔
7358
      pRateInfo->lastPk = pRateInfo->pkData + pRateInfo->pkBytes;
1,364✔
7359
    }
7360
  } else {
7361
    pRateInfo->firstPk = NULL;
2,245,918✔
7362
    pRateInfo->lastPk = NULL;
2,245,918✔
7363
  }
7364
}
2,258,876✔
7365

7366
int32_t irateFunction(SqlFunctionCtx* pCtx) {
2,199,092✔
7367
  int32_t              code = TSDB_CODE_SUCCESS;
2,199,092✔
7368
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
2,199,092✔
7369
  SRateInfo*           pRateInfo = GET_ROWCELL_INTERBUF(pResInfo);
2,199,092✔
7370

7371
  SInputColumnInfoData* pInput = &pCtx->input;
2,199,092✔
7372
  SColumnInfoData*      pInputCol = pInput->pData[0];
2,199,092✔
7373

7374
  SColumnInfoData* pOutput = (SColumnInfoData*)pCtx->pOutput;
2,199,092✔
7375

7376
  funcInputUpdate(pCtx);
2,199,092✔
7377

7378
  initializeRateInfo(pCtx, pRateInfo, false);
2,199,092✔
7379

7380
  int32_t       numOfElems = 0;
2,199,092✔
7381
  int32_t       type = pInputCol->info.type;
2,199,092✔
7382
  SFuncInputRow row = {0};
2,199,092✔
7383
  bool          result = false;
2,199,092✔
7384
  while (1) {
193,029,988✔
7385
    code = funcInputGetNextRow(pCtx, &row, &result);
195,229,080✔
7386
    if (TSDB_CODE_SUCCESS != code) {
195,229,080✔
7387
      return code;
×
7388
    }
7389
    if (!result) {
195,229,080✔
7390
      break;
2,199,092✔
7391
    }
7392
    if (row.isDataNull) {
193,029,988✔
7393
      continue;
8,483,820✔
7394
    }
7395

7396
    char*  data = row.pData;
184,546,168✔
7397
    double v = 0;
184,546,168✔
7398
    GET_TYPED_DATA(v, double, type, data, typeGetTypeModFromColInfo(&pInputCol->info));
184,546,168✔
7399

7400
    if (INT64_MIN == pRateInfo->lastKey) {
184,546,168✔
7401
      doSaveRateInfo(pRateInfo, false, row.ts, row.pPk, v);
1,320,451✔
7402
      pRateInfo->hasResult = 1;
1,320,451✔
7403
      continue;
1,320,451✔
7404
    }
7405

7406
    if (row.ts > pRateInfo->lastKey) {
183,225,717✔
7407
      if ((INT64_MIN == pRateInfo->firstKey) || pRateInfo->lastKey > pRateInfo->firstKey) {
143,959,443✔
7408
        doSaveRateInfo(pRateInfo, true, pRateInfo->lastKey, pRateInfo->lastPk, pRateInfo->lastValue);
143,959,443✔
7409
      }
7410
      doSaveRateInfo(pRateInfo, false, row.ts, row.pPk, v);
143,959,443✔
7411
      continue;
143,959,443✔
7412
    } else if (row.ts == pRateInfo->lastKey) {
39,266,274✔
7413
      return TSDB_CODE_FUNC_DUP_TIMESTAMP;
×
7414
    }
7415

7416
    if ((INT64_MIN == pRateInfo->firstKey) || row.ts > pRateInfo->firstKey) {
39,266,274✔
UNCOV
7417
      doSaveRateInfo(pRateInfo, true, row.ts, row.pPk, v);
×
7418
    } else if (row.ts == pRateInfo->firstKey) {
39,266,274✔
7419
      return TSDB_CODE_FUNC_DUP_TIMESTAMP;
×
7420
    }
7421
  }
7422

7423
  numOfElems++;
2,199,092✔
7424

7425
  SET_VAL(pResInfo, numOfElems, 1);
2,199,092✔
7426
  return TSDB_CODE_SUCCESS;
2,199,092✔
7427
}
7428

7429
static double doCalcRate(const SRateInfo* pRateInfo, double tickPerSec) {
2,089,339✔
7430
  if ((INT64_MIN == pRateInfo->lastKey) || (INT64_MIN == pRateInfo->firstKey) ||
2,089,339✔
7431
      (pRateInfo->firstKey >= pRateInfo->lastKey)) {
132,547✔
7432
    return 0.0;
1,956,792✔
7433
  }
7434

7435
  double diff = 0;
132,547✔
7436
  // If the previous value of the last is greater than the last value, only keep the last point instead of the delta
7437
  // value between two values.
7438
  diff = pRateInfo->lastValue;
132,547✔
7439
  if (diff >= pRateInfo->firstValue) {
132,547✔
7440
    diff -= pRateInfo->firstValue;
86,554✔
7441
  }
7442

7443
  int64_t duration = pRateInfo->lastKey - pRateInfo->firstKey;
132,547✔
7444
  if (duration == 0) {
132,547✔
7445
    return 0;
×
7446
  }
7447

7448
  return (duration > 0) ? ((double)diff) / (duration / tickPerSec) : 0.0;
132,547✔
7449
}
7450

7451
static void irateTransferInfoImpl(TSKEY inputKey, SRateInfo* pInput, SRateInfo* pOutput, bool isFirstKey) {
24,660✔
7452
  if (inputKey > pOutput->lastKey) {
24,660✔
7453
    doSaveRateInfo(pOutput, true, pOutput->lastKey, pOutput->lastPk, pOutput->lastValue);
7,310✔
7454
    if (isFirstKey) {
7,310✔
7455
      doSaveRateInfo(pOutput, false, pInput->firstKey, pInput->firstPk, pInput->firstValue);
3,010✔
7456
    } else {
7457
      doSaveRateInfo(pOutput, false, pInput->lastKey, pInput->lastPk, pInput->lastValue);
4,300✔
7458
    }
7459
  } else if ((inputKey < pOutput->lastKey) && (inputKey > pOutput->firstKey)) {
17,350✔
7460
    if (isFirstKey) {
2,580✔
7461
      doSaveRateInfo(pOutput, true, pInput->firstKey, pInput->firstPk, pInput->firstValue);
1,290✔
7462
    } else {
7463
      doSaveRateInfo(pOutput, true, pInput->lastKey, pInput->lastPk, pInput->lastValue);
1,290✔
7464
    }
7465
  } else {
7466
    // inputKey < pOutput->firstKey
7467
  }
7468
}
24,660✔
7469

7470
static void irateCopyInfo(SRateInfo* pInput, SRateInfo* pOutput) {
15,612✔
7471
  doSaveRateInfo(pOutput, true, pInput->firstKey, pInput->firstPk, pInput->firstValue);
15,612✔
7472
  doSaveRateInfo(pOutput, false, pInput->lastKey, pInput->lastPk, pInput->lastValue);
15,612✔
7473
}
15,612✔
7474

7475
static int32_t irateTransferInfo(SRateInfo* pInput, SRateInfo* pOutput) {
27,942✔
7476
  if ((pInput->firstKey != INT64_MIN &&
27,942✔
7477
       (pInput->firstKey == pOutput->firstKey || pInput->firstKey == pOutput->lastKey)) ||
25,342✔
7478
      (pInput->lastKey != INT64_MIN && (pInput->lastKey == pOutput->firstKey || pInput->lastKey == pOutput->lastKey))) {
27,942✔
7479
    return TSDB_CODE_FUNC_DUP_TIMESTAMP;
×
7480
  }
7481

7482
  if (pOutput->hasResult == 0) {
27,942✔
7483
    irateCopyInfo(pInput, pOutput);
15,612✔
7484
    pOutput->hasResult = pInput->hasResult;
15,612✔
7485
    return TSDB_CODE_SUCCESS;
15,612✔
7486
  }
7487

7488
  if (pInput->firstKey != INT64_MIN) {
12,330✔
7489
    irateTransferInfoImpl(pInput->firstKey, pInput, pOutput, true);
12,330✔
7490
  }
7491

7492
  if (pInput->lastKey != INT64_MIN) {
12,330✔
7493
    irateTransferInfoImpl(pInput->lastKey, pInput, pOutput, false);
12,330✔
7494
  }
7495

7496
  pOutput->hasResult = pInput->hasResult;
12,330✔
7497
  return TSDB_CODE_SUCCESS;
12,330✔
7498
}
7499

7500
int32_t irateFunctionMerge(SqlFunctionCtx* pCtx) {
29,892✔
7501
  SInputColumnInfoData* pInput = &pCtx->input;
29,892✔
7502
  SColumnInfoData*      pCol = pInput->pData[0];
29,892✔
7503
  if (pCol->info.type != TSDB_DATA_TYPE_BINARY) {
29,892✔
7504
    return TSDB_CODE_FUNC_FUNTION_PARA_TYPE;
×
7505
  }
7506

7507
  SRateInfo* pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
29,892✔
7508
  initializeRateInfo(pCtx, pInfo, true);
29,892✔
7509

7510
  int32_t start = pInput->startRowIndex;
29,892✔
7511
  for (int32_t i = start; i < start + pInput->numOfRows; ++i) {
59,784✔
7512
    char*      data = colDataGetData(pCol, i);
29,892✔
7513
    SRateInfo* pInputInfo = (SRateInfo*)varDataVal(data);
29,892✔
7514
    initializeRateInfo(pCtx, pInfo, true);
29,892✔
7515
    if (pInputInfo->hasResult) {
29,892✔
7516
      int32_t code = irateTransferInfo(pInputInfo, pInfo);
27,942✔
7517
      if (code != TSDB_CODE_SUCCESS) {
27,942✔
7518
        return code;
×
7519
      }
7520
    }
7521
  }
7522

7523
  if (pInfo->hasResult) {
29,892✔
7524
    GET_RES_INFO(pCtx)->numOfRes = 1;
27,942✔
7525
  }
7526

7527
  return TSDB_CODE_SUCCESS;
29,892✔
7528
}
7529

7530
int32_t iratePartialFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
29,892✔
7531
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
29,892✔
7532
  SRateInfo*           pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
29,892✔
7533
  int32_t              resultBytes = getIrateInfoSize(pInfo->pkBytes);
29,892✔
7534
  char*                res = taosMemoryCalloc(resultBytes + VARSTR_HEADER_SIZE, sizeof(char));
29,892✔
7535

7536
  if (NULL == res) {
29,892✔
7537
    return terrno;
×
7538
  }
7539
  (void)memcpy(varDataVal(res), pInfo, resultBytes);
29,892✔
7540
  varDataSetLen(res, resultBytes);
29,892✔
7541

7542
  int32_t          slotId = pCtx->pExpr->base.resSchema.slotId;
29,892✔
7543
  SColumnInfoData* pCol = taosArrayGet(pBlock->pDataBlock, slotId);
29,892✔
7544
  if (NULL == pCol) {
29,892✔
7545
    taosMemoryFree(res);
×
7546
    return TSDB_CODE_OUT_OF_RANGE;
×
7547
  }
7548

7549
  int32_t code = colDataSetVal(pCol, pBlock->info.rows, res, false);
29,892✔
7550

7551
  taosMemoryFree(res);
29,892✔
7552
  return code;
29,892✔
7553
}
7554

7555
int32_t irateFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
2,089,339✔
7556
  int32_t          slotId = pCtx->pExpr->base.resSchema.slotId;
2,089,339✔
7557
  SColumnInfoData* pCol = taosArrayGet(pBlock->pDataBlock, slotId);
2,089,339✔
7558
  if (NULL == pCol) {
2,089,339✔
7559
    return TSDB_CODE_OUT_OF_RANGE;
×
7560
  }
7561

7562
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
2,089,339✔
7563
  pResInfo->isNullRes = (pResInfo->numOfRes == 0) ? 1 : 0;
2,089,339✔
7564

7565
  SRateInfo* pInfo = GET_ROWCELL_INTERBUF(pResInfo);
2,089,339✔
7566
  double     result = doCalcRate(pInfo, (double)TSDB_TICK_PER_SECOND(pCtx->param[1].param.i));
2,089,339✔
7567
  int32_t    code = colDataSetVal(pCol, pBlock->info.rows, (const char*)&result, pResInfo->isNullRes);
2,089,339✔
7568

7569
  return code;
2,089,339✔
7570
}
7571

7572
int32_t groupConstValueFunction(SqlFunctionCtx* pCtx) {
2,147,483,647✔
7573
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
2,147,483,647✔
7574
  SGroupKeyInfo*       pInfo = GET_ROWCELL_INTERBUF(pResInfo);
2,147,483,647✔
7575
  bool                 isWindow = pCtx->hasWindowOrGroup && pCtx->hasWindow;
2,147,483,647✔
7576

7577
  if (pInfo->hasResult && (!isWindow || !pInfo->isNull)) {
2,147,483,647✔
7578
    // If already has result for 'group by' or
7579
    // has non-null result for 'window', we can skip left data blocks.
7580
    goto _group_value_over;
2,147,483,647✔
7581
  }
7582

7583
  int32_t               valueRowIndex = -1;
2,147,483,647✔
7584
  SInputColumnInfoData* pInput = &pCtx->input;
2,147,483,647✔
7585
  SColumnInfoData*      pInputCol = pInput->pData[0];
2,147,483,647✔
7586

7587
  // try to find a non-null value
7588
  if (NULL != pInputCol->pData) {
2,147,483,647✔
7589
    if (isWindow) {
2,147,483,647✔
7590
      // for 'window', non-null value can appear at any row of any data block
7591
      int64_t startIndex = pInput->startRowIndex;
2,147,483,647✔
7592
      int64_t endIndex = pInput->startRowIndex + pInput->numOfRows - 1;
2,147,483,647✔
7593
      for (int64_t i = startIndex; i <= endIndex; ++i) {
2,147,483,647✔
7594
        if (!colDataIsNull_s(pInputCol, i)) {
2,147,483,647✔
7595
          valueRowIndex = i;
2,147,483,647✔
7596
          break;
2,147,483,647✔
7597
        }
7598
      }
7599
    } else {
7600
      // for 'group by', just take the first row
7601
      if (!colDataIsNull_s(pInputCol, pInput->startRowIndex)) {
396,751,879✔
7602
        valueRowIndex = pInput->startRowIndex;
196,265,678✔
7603
      }
7604
    }
7605
  }
7606

7607
  if (valueRowIndex != -1) {
2,147,483,647✔
7608
    // found a non-null value
7609
    char* data = colDataGetData(pInputCol, valueRowIndex);
2,147,483,647✔
7610
    if (IS_VAR_DATA_TYPE(pInputCol->info.type)) {
2,147,483,647✔
7611
      int32_t bytes = calcStrBytesByType(pInputCol->info.type, data);
2,147,483,647✔
7612
      (void)memcpy(pInfo->data, data, bytes);
2,147,483,647✔
7613
    } else {
7614
      (void)memcpy(pInfo->data, data, pInputCol->info.bytes);
2,147,483,647✔
7615
    }
7616
    pInfo->isNull = false;
2,147,483,647✔
7617
  } else {
7618
    // all values are null or first value is null for group by
7619
    pInfo->isNull = true;
554,550,362✔
7620
  }
7621
  pInfo->hasResult = true;
2,147,483,647✔
7622

7623
_group_value_over:
2,147,483,647✔
7624
  SET_VAL(pResInfo, 1, 1);
2,147,483,647✔
7625
  return TSDB_CODE_SUCCESS;
2,147,483,647✔
7626
}
7627

7628
int32_t groupKeyFunction(SqlFunctionCtx* pCtx) { return groupConstValueFunction(pCtx); }
2,147,483,647✔
7629

7630
int32_t groupConstValueFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
2,147,483,647✔
7631
  int32_t          slotId = pCtx->pExpr->base.resSchema.slotId;
2,147,483,647✔
7632
  int32_t          code = TSDB_CODE_SUCCESS;
2,147,483,647✔
7633
  SColumnInfoData* pCol = taosArrayGet(pBlock->pDataBlock, slotId);
2,147,483,647✔
7634
  if (NULL == pCol) {
2,147,483,647✔
7635
    return TSDB_CODE_OUT_OF_RANGE;
×
7636
  }
7637

7638
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
2,147,483,647✔
7639

7640
  SGroupKeyInfo* pInfo = GET_ROWCELL_INTERBUF(pResInfo);
2,147,483,647✔
7641

7642
  if (pInfo->hasResult) {
2,147,483,647✔
7643
    int32_t currentRow = pBlock->info.rows;
2,147,483,647✔
7644
    for (; currentRow < pBlock->info.rows + pResInfo->numOfRes; ++currentRow) {
2,147,483,647✔
7645
      code = colDataSetVal(pCol, currentRow, pInfo->data, pInfo->isNull ? true : false);
2,147,483,647✔
7646
      if (TSDB_CODE_SUCCESS != code) {
2,147,483,647✔
7647
        return code;
×
7648
      }
7649
    }
7650
  } else {
7651
    pResInfo->numOfRes = 0;
×
7652
  }
7653

7654
  return code;
2,147,483,647✔
7655
}
7656

7657
int32_t groupKeyFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) { return groupConstValueFinalize(pCtx, pBlock); }
2,147,483,647✔
7658

7659
int32_t groupKeyCombine(SqlFunctionCtx* pDestCtx, SqlFunctionCtx* pSourceCtx) {
×
7660
  SResultRowEntryInfo* pDResInfo = GET_RES_INFO(pDestCtx);
×
7661
  SGroupKeyInfo*       pDBuf = GET_ROWCELL_INTERBUF(pDResInfo);
×
7662

7663
  SResultRowEntryInfo* pSResInfo = GET_RES_INFO(pSourceCtx);
×
7664
  SGroupKeyInfo*       pSBuf = GET_ROWCELL_INTERBUF(pSResInfo);
×
7665

7666
  // escape rest of data blocks to avoid first entry to be overwritten.
7667
  if (pDBuf->hasResult) {
×
7668
    goto _group_key_over;
×
7669
  }
7670

7671
  if (pSBuf->isNull) {
×
7672
    pDBuf->isNull = true;
×
7673
    pDBuf->hasResult = true;
×
7674
    goto _group_key_over;
×
7675
  }
7676

7677
  if (IS_VAR_DATA_TYPE(pSourceCtx->resDataInfo.type)) {
×
7678
    int32_t bytes = calcStrBytesByType(pSourceCtx->resDataInfo.type, pSBuf->data);
×
7679
    (void)memcpy(pDBuf->data, pSBuf->data, bytes);
×
7680
  } else {
7681
    (void)memcpy(pDBuf->data, pSBuf->data, pSourceCtx->resDataInfo.bytes);
×
7682
  }
7683

7684
  pDBuf->hasResult = true;
×
7685

7686
_group_key_over:
×
7687

7688
  SET_VAL(pDResInfo, 1, 1);
×
7689
  return TSDB_CODE_SUCCESS;
×
7690
}
7691

7692
int32_t cachedLastRowFunction(SqlFunctionCtx* pCtx) {
569,858✔
7693
  int32_t numOfElems = 0;
569,858✔
7694

7695
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
569,858✔
7696
  SFirstLastRes*       pInfo = GET_ROWCELL_INTERBUF(pResInfo);
569,858✔
7697

7698
  SInputColumnInfoData* pInput = &pCtx->input;
569,858✔
7699
  SColumnInfoData*      pInputCol = pInput->pData[0];
569,858✔
7700

7701
  int32_t bytes = pInputCol->info.bytes;
569,858✔
7702
  pInfo->bytes = bytes;
569,858✔
7703

7704
  SColumnInfoData* pkCol = pInput->pPrimaryKey;
569,858✔
7705
  pInfo->pkType = -1;
569,858✔
7706
  __compar_fn_t pkCompareFn = NULL;
569,858✔
7707
  if (pCtx->hasPrimaryKey) {
569,858✔
7708
    pInfo->pkType = pkCol->info.type;
184,776✔
7709
    pInfo->pkBytes = pkCol->info.bytes;
184,776✔
7710
    pkCompareFn = getKeyComparFunc(pInfo->pkType, TSDB_ORDER_DESC);
184,776✔
7711
  }
7712

7713
  // data is guaranteed to be in descending order
7714
  for (int32_t i = pInput->numOfRows + pInput->startRowIndex - 1; i >= pInput->startRowIndex; --i) {
1,196,640✔
7715
    numOfElems++;
626,782✔
7716

7717
    bool  isNull = colDataIsNull(pInputCol, pInput->numOfRows, i, NULL);
626,782✔
7718
    char* data = isNull ? NULL : colDataGetData(pInputCol, i);
626,782✔
7719

7720
    TSKEY cts = getRowPTs(pInput->pPTS, i);
626,782✔
7721
    if (pResInfo->numOfRes == 0 || pInfo->ts < cts) {
626,782✔
7722
      int32_t code = doSaveLastrow(pCtx, data, i, cts, pInfo);
502,363✔
7723
      if (code != TSDB_CODE_SUCCESS) {
502,363✔
7724
        return code;
×
7725
      }
7726
      pResInfo->numOfRes = 1;
502,363✔
7727
    }
7728
  }
7729

7730
  SET_VAL(pResInfo, numOfElems, 1);
569,858✔
7731
  return TSDB_CODE_SUCCESS;
569,858✔
7732
}
7733

7734
bool getCorrFuncEnv(SFunctionNode* pFunc, SFuncExecEnv* pEnv) {
×
7735
  pEnv->calcMemSize = sizeof(SCorrRes);
×
7736
  return true;
×
7737
}
7738

7739
int32_t corrFuncSetup(SqlFunctionCtx* pCtx, SResultRowEntryInfo* pResultInfo) {
×
7740
  if (pResultInfo->initialized) {
×
7741
    return TSDB_CODE_SUCCESS;
×
7742
  }
7743
  if (TSDB_CODE_SUCCESS != functionSetup(pCtx, pResultInfo)) {
×
7744
    return TSDB_CODE_FUNC_SETUP_ERROR;
×
7745
  }
7746

7747
  SCorrRes* pRes = GET_ROWCELL_INTERBUF(pResultInfo);
×
7748
  (void)memset(pRes, 0, sizeof(SCorrRes));
×
7749
  return TSDB_CODE_SUCCESS;
×
7750
}
7751

7752
int32_t corrFunction(SqlFunctionCtx* pCtx) {
×
7753
  int32_t               numOfElem = 0;
×
7754
  SInputColumnInfoData* pInput = &pCtx->input;
×
7755
  int32_t               xType = pInput->pData[0]->info.type;
×
7756
  int32_t               yType = pInput->pData[1]->info.type;
×
7757
  SCorrRes*             pCorrRes = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
×
7758

7759
  // computing based on the true data block
7760
  SColumnInfoData* pLeft = pInput->pData[0];   // left
×
7761
  SColumnInfoData* pRight = pInput->pData[1];  // right
×
7762

7763
  int32_t leftMod = typeGetTypeModFromColInfo(&pLeft->info);
×
7764
  int32_t rightMod = typeGetTypeModFromColInfo(&pRight->info);
×
7765
  int32_t start = pInput->startRowIndex;
×
7766
  int32_t numOfRows = pInput->numOfRows;
×
7767

7768
  if (IS_NULL_TYPE(xType) || IS_NULL_TYPE(yType)) {
×
7769
    numOfElem = 0;
×
7770
    goto _over;
×
7771
  }
7772

7773
  for (int32_t i = 0; i < numOfRows; ++i) {
×
7774
    double pInputX = 0, pInputY = 0;
×
7775

7776
    if (colDataIsNull_f(pLeft, i) || colDataIsNull_f(pRight, i)) {
×
7777
      continue;
×
7778
    }
7779

7780
    char* pXVal = colDataGetData(pLeft, i);
×
7781
    char* pYVal = colDataGetData(pRight, i);
×
7782

7783
    GET_TYPED_DATA(pInputX, double, xType, pXVal, leftMod);
×
7784
    GET_TYPED_DATA(pInputY, double, yType, pYVal, rightMod);
×
7785

7786
    pCorrRes->sumLeft += pInputX;
×
7787
    pCorrRes->sumRight += pInputY;
×
7788

7789
    pCorrRes->quadLeft += pInputX * pInputX;
×
7790
    pCorrRes->quadRight += pInputY * pInputY;
×
7791

7792
    pCorrRes->productVal += pInputX * pInputY;
×
7793

7794
    pCorrRes->count += 1;
×
7795
    numOfElem += 1;
×
7796
  }
7797

7798
_over:
×
7799
  // data in the check operation are all null, not output
7800
  SET_VAL(GET_RES_INFO(pCtx), numOfElem, 1);
×
7801
  return TSDB_CODE_SUCCESS;
×
7802
}
7803

7804
int32_t corrFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
×
7805
  SInputColumnInfoData* pInput = &pCtx->input;
×
7806
  SCorrRes*             pRes = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
×
7807
  double                avg;
7808

7809
  if (pRes->count == 0) {
×
7810
    GET_RES_INFO(pCtx)->numOfRes = 0;
×
7811
    return functionFinalize(pCtx, pBlock);
×
7812
  }
7813

7814
  /**
7815
    numerator = sum_xy - (sum_x * sum_y) / n
7816
    denominator_x = math.sqrt(sum_x2 - (sum_x**2) / n)
7817
    denominator_y = math.sqrt(sum_y2 - (sum_y**2) / n)
7818

7819
    if denominator_x == 0 or denominator_y == 0:
7820
        return 0.0
7821
    res = numerator / (denominator_x * denominator_y)
7822
  */
7823

7824
  if (pRes->count == 1) {
×
7825
    pRes->result = 0.0;
×
7826
  } else {
7827
    double numerator = pRes->productVal - (pRes->sumLeft * pRes->sumRight) / pRes->count;
×
7828
    double dnmX = sqrt(pRes->quadLeft - pRes->sumLeft * pRes->sumLeft / pRes->count);
×
7829
    double dnmY = sqrt(pRes->quadRight - pRes->sumRight * pRes->sumRight / pRes->count);
×
7830

7831
    if (DBL_EQUAL(dnmX, 0.0) || DBL_EQUAL(dnmY, 0.0)) {
×
7832
      pRes->result = 0.0;
×
7833
    } else {
7834
      pRes->result = numerator / (dnmX * dnmY);
×
7835

7836
      if (pRes->result > 1 || pRes->result < -1) {
×
7837
        qError("invalid corr results, %.4f, numerator:%.4f, dnmX:%.4f, dnmY:%.4f", pRes->result, numerator, dnmX, dnmY);
×
7838
        if (pRes->result > 1) {
×
7839
          pRes->result = 1;
×
7840
        } else if (pRes->result < -1) {
×
7841
          pRes->result = -1;
×
7842
        }
7843
      }
7844
    }
7845
  }
7846

7847
  return functionFinalize(pCtx, pBlock);
×
7848
}
7849

7850
int32_t getCorrInfoSize() { return sizeof(SCorrRes); }
×
7851

7852
int32_t corrPartialFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
×
7853
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
×
7854
  SStdRes*             pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
×
7855
  int32_t              resultBytes = getCorrInfoSize();
×
7856
  char*                res = taosMemoryCalloc(resultBytes + VARSTR_HEADER_SIZE, sizeof(char));
×
7857
  int32_t              slotId = pCtx->pExpr->base.resSchema.slotId;
×
7858
  int32_t              code = 0;
×
7859

7860
  if (NULL == res) {
×
7861
    return terrno;
×
7862
  }
7863

7864
  (void)memcpy(varDataVal(res), pInfo, resultBytes);
×
7865
  varDataSetLen(res, resultBytes);
×
7866

7867
  SColumnInfoData* pCol = taosArrayGet(pBlock->pDataBlock, slotId);
×
7868
  if (NULL == pCol) {
×
7869
    taosMemoryFree(res);
×
7870
    return TSDB_CODE_OUT_OF_RANGE;
×
7871
  }
7872

7873
  code = colDataSetVal(pCol, pBlock->info.rows, res, false);
×
7874

7875
  taosMemoryFree(res);
×
7876
  return code;
×
7877
}
7878

7879
int32_t corrFuncMerge(SqlFunctionCtx* pCtx) {
×
7880
  SInputColumnInfoData* pInput = &pCtx->input;
×
7881
  SColumnInfoData*      pCol = pInput->pData[0];
×
7882

7883
  if (IS_NULL_TYPE(pCol->info.type)) {
×
7884
    SET_VAL(GET_RES_INFO(pCtx), 0, 1);
×
7885
    return TSDB_CODE_SUCCESS;
×
7886
  }
7887

7888
  if (pCol->info.type != TSDB_DATA_TYPE_BINARY) {
×
7889
    return TSDB_CODE_FUNC_FUNTION_PARA_TYPE;
×
7890
  }
7891

7892
  SCorrRes* pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
×
7893

7894
  for (int32_t i = pInput->startRowIndex; i < pInput->startRowIndex + pInput->numOfRows; ++i) {
×
7895
    if (colDataIsNull_s(pCol, i)) {
×
7896
      continue;
×
7897
    }
7898

7899
    char*     data = colDataGetData(pCol, i);
×
7900
    SCorrRes* pInputInfo = (SCorrRes*)varDataVal(data);
×
7901

7902
    if (pInputInfo->count == 0) {
×
7903
      continue;
×
7904
    }
7905

7906
    // pOutput->type = pInput->type;
7907
    if (pInfo->count == 0) {
×
7908
      TAOS_MEMCPY(pInfo, pInputInfo, sizeof(SCorrRes));
×
7909
    } else if (pInfo->count > 0) {
×
7910
      pInfo->productVal += pInputInfo->productVal;
×
7911
      pInfo->quadLeft += pInputInfo->quadLeft;
×
7912
      pInfo->quadRight += pInputInfo->quadRight;
×
7913
      pInfo->sumLeft += pInputInfo->sumLeft;
×
7914
      pInfo->sumRight += pInputInfo->sumRight;
×
7915
      pInfo->count += pInputInfo->count;
×
7916
    }
7917
  }
7918

7919
  SET_VAL(GET_RES_INFO(pCtx), pInfo->count, 1);
×
7920
  return TSDB_CODE_SUCCESS;
×
7921
}
7922

7923
int32_t hasNullFunction(SqlFunctionCtx* pCtx) {
15,262,780✔
7924
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
15,262,780✔
7925
  bool* pRes = GET_ROWCELL_INTERBUF(pResInfo);
15,262,780✔
7926
  if (*pRes) {
15,262,780✔
7927
    return TSDB_CODE_SUCCESS;
×
7928
  }
7929

7930
  SInputColumnInfoData* pInput = &pCtx->input;
15,262,780✔
7931
  SColumnDataAgg*       pAgg = pInput->pColumnDataAgg[0];
15,262,780✔
7932
  SColumnInfoData* pCol = pInput->pData[0];
15,262,780✔
7933

7934
  if (pInput->numOfRows > 0) {
15,262,780✔
7935
    pResInfo->numOfRes = 1;
15,262,780✔
7936
  }
7937

7938
  if (IS_NULL_TYPE(pCol->info.type) && pInput->numOfRows > 0) {
15,262,780✔
7939
    *pRes = true;
×
7940
    return TSDB_CODE_SUCCESS;
×
7941
  }
7942

7943
  if (pInput->colDataSMAIsSet) {
15,262,780✔
7944
    if (pAgg->numOfNull > 0) {
×
7945
      *pRes = true;
×
7946
      return TSDB_CODE_SUCCESS;
×
7947
    }
7948

7949
    if (pInput->numOfRows <= INT16_MAX) {
×
7950
      return TSDB_CODE_SUCCESS;
×
7951
    }
7952
  }
7953

7954
  int32_t start = pInput->startRowIndex;
15,262,780✔
7955
  int32_t end = start + pInput->numOfRows;
15,262,780✔
7956

7957
  if (pCol->hasNull) {
15,262,780✔
7958
    for (int32_t i = start; i < end; ++i) {
36,330,844✔
7959
      if (colDataIsNull_s(pCol, i)) {
61,598,032✔
7960
        *pRes = true;
9,642,474✔
7961
        break;
9,642,474✔
7962
      }
7963
    }
7964
  }  
7965

7966
  return TSDB_CODE_SUCCESS;
15,262,780✔
7967
}
7968

7969

7970

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