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

taosdata / TDengine / #4892

20 Dec 2025 01:15PM UTC coverage: 65.571% (+0.02%) from 65.549%
#4892

push

travis-ci

web-flow
feat: support taos_connect_with func (#33952)

* feat: support taos_connect_with

* refactor: enhance connection options and add tests for taos_set_option and taos_connect_with

* fix: handle NULL keys and values in taos_connect_with options

* fix: revert TAOSWS_GIT_TAG to default value "main"

* docs: add TLS configuration options for WebSocket connections in documentation

* docs: modify zh docs and add en docs

* chore: update taos.cfg

* docs: add examples

* docs: add error handling for connection failure in example code

2 of 82 new or added lines in 3 files covered. (2.44%)

527 existing lines in 120 files now uncovered.

182859 of 278870 relevant lines covered (65.57%)

104634355.9 hits per line

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

76.4
/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; }
17,217,557✔
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) {
25,282,676✔
198
  SFuncInputRowIter* pIter = &pCtx->rowIter;
25,282,676✔
199

200
  if (!pCtx->bInputFinished) {
25,282,676✔
201
    pIter->pInput = &pCtx->input;
25,282,676✔
202
    pIter->tsList = (TSKEY*)pIter->pInput->pPTS->pData;
25,282,676✔
203
    pIter->pDataCol = pIter->pInput->pData[0];
25,282,676✔
204
    pIter->pPkCol = pIter->pInput->pPrimaryKey;
25,282,173✔
205
    pIter->rowIndex = pIter->pInput->startRowIndex;
25,282,676✔
206
    pIter->inputEndIndex = pIter->rowIndex + pIter->pInput->numOfRows - 1;
25,282,676✔
207
    pIter->pSrcBlock = pCtx->pSrcBlock;
25,282,676✔
208
    if (!pIter->hasGroupId || pIter->groupId != pIter->pSrcBlock->info.id.groupId) {
25,282,676✔
209
      pIter->hasGroupId = true;
2,503,994✔
210
      pIter->groupId = pIter->pSrcBlock->info.id.groupId;
2,504,497✔
211
      pIter->hasPrev = false;
2,504,497✔
212
    }
213
  } else {
214
    pIter->finalRow = true;
×
215
  }
216
}
25,282,676✔
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) {
35,504✔
333
  int32_t idx = rowIndex + 1;
35,504✔
334
  while (idx <= pIter->inputEndIndex && pIter->tsList[idx] == pIter->tsList[rowIndex]) {
81,074✔
335
    ++idx;
45,570✔
336
  }
337
  pIter->rowIndex = idx;
35,504✔
338
}
35,504✔
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) {
69,986✔
351
  if (pIter->hasPrev) {
69,986✔
352
    if (pIter->prevBlockTsEnd == pIter->tsList[pIter->inputEndIndex]) {
×
353
      pIter->hasPrev = true;
×
354
      return false;
×
355
    } else {
356
      int32_t idx = pIter->rowIndex;
×
357
      while (pIter->tsList[idx] == pIter->prevBlockTsEnd) {
×
358
        ++idx;
×
359
      }
360

361
      pIter->hasPrev = false;
×
362
      setInputRowInfo(pRow, pIter, idx, true);
×
363
      forwardToNextDiffTsRow(pIter, idx);
×
364
      return true;
×
365
    }
366
  } else {
367
    if (pIter->rowIndex <= pIter->inputEndIndex) {
69,986✔
368
      setInputRowInfo(pRow, pIter, pIter->rowIndex, true);
53,256✔
369

370
      TSKEY tsEnd = pIter->tsList[pIter->inputEndIndex];
53,256✔
371
      if (pIter->tsList[pIter->rowIndex] != tsEnd) {
53,256✔
372
        forwardToNextDiffTsRow(pIter, pIter->rowIndex);
35,504✔
373
      } else {
374
        pIter->rowIndex = pIter->inputEndIndex + 1;
17,752✔
375
      }
376
      return true;
53,256✔
377
    } else {
378
      TSKEY tsEnd = pIter->tsList[pIter->inputEndIndex];
16,730✔
379
      pIter->hasPrev = true;
16,730✔
380
      pIter->prevBlockTsEnd = tsEnd;
16,730✔
381
      return false;
16,730✔
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;
25,556,528✔
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) {
69,986✔
400
      return funcInputGetNextRowDescPk(pIter, pRow, res);
×
401
      return TSDB_CODE_SUCCESS;
402
    } else {
403
      *res = funcInputGetNextRowAscPk(pIter, pRow);
69,986✔
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;
69,986✔
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,553✔
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,408,989✔
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) {
96,602✔
502
  int32_t          slotId = pCtx->pExpr->base.resSchema.slotId;
96,602✔
503
  SColumnInfoData* pCol = taosArrayGet(pBlock->pDataBlock, slotId);
96,602✔
504
  if (NULL == pCol) {
96,602✔
505
    return TSDB_CODE_OUT_OF_RANGE;
×
506
  }
507
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
96,602✔
508
  pResInfo->isNullRes = (pResInfo->numOfRes == 0) ? 1 : 0;
96,602✔
509

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

513
  return code;
96,602✔
514
}
515

516
EFuncDataRequired countDataRequired(SFunctionNode* pFunc, STimeWindow* pTimeWindow) {
5,394,294✔
517
  SNode* pParam = nodesListGetNode(pFunc->pParameterList, 0);
5,394,294✔
518
  if (QUERY_NODE_COLUMN == nodeType(pParam) && PRIMARYKEY_TIMESTAMP_COL_ID == ((SColumnNode*)pParam)->colId) {
5,394,814✔
519
    return FUNC_DATA_REQUIRED_NOT_LOAD;
3,517,801✔
520
  }
521
  return FUNC_DATA_REQUIRED_SMA_LOAD;
1,877,013✔
522
}
523

524
bool getCountFuncEnv(SFunctionNode* UNUSED_PARAM(pFunc), SFuncExecEnv* pEnv) {
23,834,873✔
525
  pEnv->calcMemSize = sizeof(int64_t);
23,834,873✔
526
  return true;
23,838,764✔
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;
16,430,017✔
541
  }
542
  if (pInput->colDataSMAIsSet && pInput->totalRows == pInput->numOfRows) {
2,147,483,647✔
543
    numOfElem = pInput->numOfRows - pInput->pColumnDataAgg[0]->numOfNull;
176,606✔
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;
3,126,852✔
578
    val += 0;
3,126,852✔
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);
2,305,915✔
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;
304,705✔
620
    goto _sum_over;
304,705✔
621
  }
622

623
  if (pInput->colDataSMAIsSet) {
2,147,483,647✔
624
    numOfElem = pInput->numOfRows - pAgg->numOfNull;
1,487,261✔
625

626
    if (IS_SIGNED_NUMERIC_TYPE(type)) {
1,487,261✔
627
      SUM_RES_INC_ISUM(pSumRes, pAgg->sum);
1,478,780✔
628
    } else if (IS_UNSIGNED_NUMERIC_TYPE(type)) {
8,481✔
629
      SUM_RES_INC_USUM(pSumRes, pAgg->sum);
×
630
    } else if (IS_FLOAT_TYPE(type)) {
8,481✔
631
      SUM_RES_INC_DSUM(pSumRes, GET_DOUBLE_VAL((const char*)&(pAgg->sum)));
×
632
    } else if (IS_DECIMAL_TYPE(type)) {
8,481✔
633
      SUM_RES_SET_TYPE(pSumRes, pCtx->inputType, TSDB_DATA_TYPE_DECIMAL);
8,481✔
634
      const SDecimalOps* pOps = getDecimalOps(TSDB_DATA_TYPE_DECIMAL);
8,481✔
635
      if (pAgg->overflow || decimal128AddCheckOverflow((Decimal*)&SUM_RES_GET_DECIMAL_SUM(pSumRes),
15,420✔
636
                                                       &pAgg->decimal128Sum, DECIMAL_WORD_NUM(Decimal))) {
6,939✔
637
        return TSDB_CODE_DECIMAL_OVERFLOW;
1,542✔
638
      }
639
      pOps->add(&SUM_RES_GET_DECIMAL_SUM(pSumRes), &pAgg->decimal128Sum, DECIMAL_WORD_NUM(Decimal));
6,939✔
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);
190,322,121✔
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);
113,674,041✔
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) {
680,898,112✔
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)) {
154,897,612✔
658
      if (type == TSDB_DATA_TYPE_UTINYINT) {
396,523✔
659
        LIST_ADD_N(SUM_RES_GET_USUM(pSumRes), pCol, start, numOfRows, uint8_t, numOfElem);
25,216,787✔
660
      } else if (type == TSDB_DATA_TYPE_USMALLINT) {
385,736✔
661
        LIST_ADD_N(SUM_RES_GET_USUM(pSumRes), pCol, start, numOfRows, uint16_t, numOfElem);
890,099,312✔
662
      } else if (type == TSDB_DATA_TYPE_UINT) {
146,053✔
663
        LIST_ADD_N(SUM_RES_GET_USUM(pSumRes), pCol, start, numOfRows, uint32_t, numOfElem);
25,520,472✔
664
      } else if (type == TSDB_DATA_TYPE_UBIGINT) {
53,741✔
665
        LIST_ADD_N(SUM_RES_GET_USUM(pSumRes), pCol, start, numOfRows, uint64_t, numOfElem);
25,336,850✔
666
      }
667
    } else if (type == TSDB_DATA_TYPE_DOUBLE) {
154,501,089✔
668
      LIST_ADD_N(SUM_RES_GET_DSUM(pSumRes), pCol, start, numOfRows, double, numOfElem);
266,365,188✔
669
    } else if (type == TSDB_DATA_TYPE_FLOAT) {
108,427,589✔
670
      LIST_ADD_N(SUM_RES_GET_DSUM(pSumRes), pCol, start, numOfRows, float, numOfElem);
300,224,179✔
671
    } else if (IS_DECIMAL_TYPE(type)) {
41,572✔
672
      SUM_RES_SET_TYPE(pSumRes, pCtx->inputType, TSDB_DATA_TYPE_DECIMAL);
41,572✔
673
      int32_t overflow = false;
23,130✔
674
      if (TSDB_DATA_TYPE_DECIMAL64 == type) {
23,130✔
675
        LIST_ADD_DECIMAL_N(&SUM_RES_GET_DECIMAL_SUM(pSumRes), pCol, start, numOfRows, Decimal64, numOfElem);
6,174,168✔
676
      } else if (TSDB_DATA_TYPE_DECIMAL == type) {
16,962✔
677
        LIST_ADD_DECIMAL_N(&SUM_RES_GET_DECIMAL_SUM(pSumRes), pCol, start, numOfRows, Decimal128, numOfElem);
12,357,588✔
678
      }
679
      if (overflow) return TSDB_CODE_DECIMAL_OVERFLOW;
23,130✔
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 &&
75,073,151✔
691
        fmIsCountLikeFunc(pCtx->pExpr->pExpr->_function.pFunctNode->originalFuncId)) {
23,209,698✔
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) {
14,833,283✔
725
  pEnv->calcMemSize = SUM_RES_GET_SIZE(pFunc->node.resType.type);
14,833,283✔
726
  return true;
14,834,490✔
727
}
728

729
static bool funcNotSupportStringSma(SFunctionNode* pFunc) {
4,720,279✔
730
  SNode* pParam;
731
  switch (pFunc->funcType) {
4,720,279✔
732
    case FUNCTION_TYPE_MAX:
4,720,279✔
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);
4,720,279✔
744
      if (pParam && nodesIsExprNode(pParam) && (IS_VAR_DATA_TYPE(((SExprNode*)pParam)->resType.type))) {
4,720,279✔
745
        return true;
33,356✔
746
      }
747
      break;
4,686,923✔
748
    default:
×
749
      break;
×
750
  }
751
  return false;
4,686,923✔
752
}
753

754
EFuncDataRequired statisDataRequired(SFunctionNode* pFunc, STimeWindow* pTimeWindow) {
4,720,279✔
755
  if (funcNotSupportStringSma(pFunc)) {
4,720,279✔
756
    return FUNC_DATA_REQUIRED_DATA_LOAD;
33,356✔
757
  }
758
  return FUNC_DATA_REQUIRED_SMA_LOAD;
4,686,923✔
759
}
760

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

769
  SMinmaxResInfo* buf = GET_ROWCELL_INTERBUF(pResultInfo);
400,502,376✔
770
  buf->assign = false;
400,500,171✔
771
  buf->tuplePos.pageId = -1;
400,504,858✔
772

773
  buf->nullTupleSaved = false;
400,501,476✔
774
  buf->nullTuplePos.pageId = -1;
400,510,641✔
775
  buf->str = NULL;
400,501,449✔
776
  return TSDB_CODE_SUCCESS;
400,509,026✔
777
}
778

779
bool getMinmaxFuncEnv(SFunctionNode* UNUSED_PARAM(pFunc), SFuncExecEnv* pEnv) {
5,922,871✔
780
  COMPILE_TIME_ASSERT(sizeof(SMinmaxResInfo) == sizeof(SOldMinMaxResInfo));
781
  pEnv->calcMemSize = sizeof(SMinmaxResInfo);
5,922,871✔
782
  return true;
5,923,429✔
783
}
784

785
int32_t minFunction(SqlFunctionCtx* pCtx) {
235,627,596✔
786
  int32_t numOfElems = 0;
235,627,596✔
787
  int32_t code = doMinMaxHelper(pCtx, 1, &numOfElems);
235,715,037✔
788
  if (code != TSDB_CODE_SUCCESS) {
235,838,144✔
789
    return code;
×
790
  }
791
  SET_VAL(GET_RES_INFO(pCtx), numOfElems, 1);
235,838,144✔
792
  return TSDB_CODE_SUCCESS;
235,749,199✔
793
}
794

795
int32_t maxFunction(SqlFunctionCtx* pCtx) {
317,010,929✔
796
  int32_t numOfElems = 0;
317,010,929✔
797
  int32_t code = doMinMaxHelper(pCtx, 0, &numOfElems);
317,188,736✔
798
  if (code != TSDB_CODE_SUCCESS) {
317,177,414✔
799
    return code;
×
800
  }
801
  SET_VAL(GET_RES_INFO(pCtx), numOfElems, 1);
317,177,414✔
802
  return TSDB_CODE_SUCCESS;
316,972,336✔
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) {
372,901,042✔
810
  int32_t code = TSDB_CODE_SUCCESS;
372,901,042✔
811

812
  SResultRowEntryInfo* pEntryInfo = GET_RES_INFO(pCtx);
372,901,042✔
813
  SMinmaxResInfo*      pRes = GET_ROWCELL_INTERBUF(pEntryInfo);
372,904,329✔
814

815
  int32_t slotId = pCtx->pExpr->base.resSchema.slotId;
372,903,138✔
816
  int32_t currentRow = pBlock->info.rows;
372,905,871✔
817

818
  SColumnInfoData* pCol = taosArrayGet(pBlock->pDataBlock, slotId);
372,904,051✔
819
  if (NULL == pCol) {
372,895,587✔
820
    return TSDB_CODE_OUT_OF_RANGE;
×
821
  }
822
  pEntryInfo->isNullRes = (pEntryInfo->numOfRes == 0) ? 1 : 0;
372,895,587✔
823

824
  // NOTE: do nothing change it, for performance issue
825
  if (!pEntryInfo->isNullRes) {
372,895,212✔
826
    switch (pCol->info.type) {
314,516,581✔
827
      case TSDB_DATA_TYPE_UBIGINT:
103,520,099✔
828
      case TSDB_DATA_TYPE_BIGINT:
829
        ((int64_t*)pCol->pData)[currentRow] = pRes->v;
103,520,099✔
830
        break;
103,518,991✔
831
      case TSDB_DATA_TYPE_UINT:
174,092,561✔
832
      case TSDB_DATA_TYPE_INT:
833
        colDataSetInt32(pCol, currentRow, (int32_t*)&pRes->v);
174,092,561✔
834
        break;
174,089,001✔
835
      case TSDB_DATA_TYPE_USMALLINT:
1,274,791✔
836
      case TSDB_DATA_TYPE_SMALLINT:
837
        colDataSetInt16(pCol, currentRow, (int16_t*)&pRes->v);
1,274,791✔
838
        break;
1,274,791✔
839
      case TSDB_DATA_TYPE_BOOL:
10,549,943✔
840
      case TSDB_DATA_TYPE_UTINYINT:
841
      case TSDB_DATA_TYPE_TINYINT:
842
        colDataSetInt8(pCol, currentRow, (int8_t*)&pRes->v);
10,549,943✔
843
        break;
10,549,943✔
844
      case TSDB_DATA_TYPE_DOUBLE:
12,642,922✔
845
        colDataSetDouble(pCol, currentRow, (double*)&pRes->v);
12,642,922✔
846
        break;
12,642,922✔
847
      case TSDB_DATA_TYPE_FLOAT: {
10,928,484✔
848
        float v = GET_FLOAT_VAL(&pRes->v);
10,928,484✔
849
        colDataSetFloat(pCol, currentRow, &v);
10,928,484✔
850
        break;
10,928,484✔
851
      }
852
      case TSDB_DATA_TYPE_VARBINARY:
1,453,096✔
853
      case TSDB_DATA_TYPE_VARCHAR:
854
      case TSDB_DATA_TYPE_NCHAR: {
855
        code = colDataSetVal(pCol, currentRow, pRes->str, false);
1,453,096✔
856
        if (TSDB_CODE_SUCCESS != code) {
1,453,096✔
857
          return code;
×
858
        }
859
        break;
1,453,096✔
860
      }
861
      case TSDB_DATA_TYPE_DECIMAL64:
26,527✔
862
        code = colDataSetVal(pCol, currentRow, (const char*)&pRes->v, false);
26,527✔
863
        break;
26,527✔
864
      case TSDB_DATA_TYPE_DECIMAL:
33,291✔
865
        code = colDataSetVal(pCol, currentRow, (void*)pRes->dec, false);
33,291✔
866
        break;
33,291✔
867
    }
868
  } else {
869
    colDataSetNULL(pCol, currentRow);
58,381,834✔
870
  }
871

872
  if (IS_VAR_DATA_TYPE(pCol->info.type)) taosMemoryFreeClear(pRes->str);
372,883,611✔
873
  if (pCtx->subsidiaries.num > 0) {
372,895,212✔
874
    if (pEntryInfo->numOfRes > 0) {
682,955✔
875
      code = setSelectivityValue(pCtx, pBlock, &pRes->tuplePos, currentRow);
567,926✔
876
    } else {
877
      code = setNullSelectivityValue(pCtx, pBlock, currentRow);
114,518✔
878
    }
879
  }
880

881
  return code;
372,894,030✔
882
}
883

884
int32_t setNullSelectivityValue(SqlFunctionCtx* pCtx, SSDataBlock* pBlock, int32_t rowIndex) {
662,057,590✔
885
  if (pCtx->subsidiaries.num <= 0) {
662,057,590✔
886
    return TSDB_CODE_SUCCESS;
661,868,102✔
887
  }
888

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

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

900
  return TSDB_CODE_SUCCESS;
202,409✔
901
}
902

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

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

919
    bool* nullList = (bool*)p;
13,438,725✔
920
    char* pStart = (char*)(nullList + numOfCols * sizeof(bool));
13,438,725✔
921

922
    // todo set the offset value to optimize the performance.
923
    for (int32_t j = 0; j < numOfCols; ++j) {
30,407,251✔
924
      SqlFunctionCtx* pc = pCtx->subsidiaries.pCtx[j];
16,968,015✔
925
      int32_t         dstSlotId = pc->pExpr->base.resSchema.slotId;
16,968,015✔
926

927
      SColumnInfoData* pDstCol = taosArrayGet(pBlock->pDataBlock, dstSlotId);
16,966,482✔
928
      if (NULL == pDstCol) {
16,965,943✔
929
        return terrno;
×
930
      }
931
      if (nullList[j]) {
16,965,943✔
932
        colDataSetNULL(pDstCol, rowIndex);
49,170✔
933
      } else {
934
        code = colDataSetValOrCover(pDstCol, rowIndex, pStart, false);
16,918,845✔
935
        if (TSDB_CODE_SUCCESS != code) {
16,918,845✔
936
          return code;
×
937
        }
938
      }
939
      pStart += pDstCol->info.bytes;
16,968,015✔
940
    }
941
  }
942

943
  return TSDB_CODE_SUCCESS;
13,439,236✔
944
}
945

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

953
  int32_t code = TSDB_CODE_SUCCESS;
213,758✔
954
  for (int32_t j = 0; j < pCtx->subsidiaries.num; ++j) {
735,058✔
955
    SqlFunctionCtx* pc = pCtx->subsidiaries.pCtx[j];
521,300✔
956

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

961
    SColumnInfoData* pSrcCol = taosArrayGet(pCtx->pSrcBlock->pDataBlock, srcSlotId);
521,300✔
962
    if (NULL == pSrcCol) {
521,300✔
963
      return TSDB_CODE_OUT_OF_RANGE;
×
964
    }
965

966
    char* pData = colDataGetData(pSrcCol, rowIndex);
521,300✔
967

968
    // append to dest col
969
    int32_t dstSlotId = pc->pExpr->base.resSchema.slotId;
521,300✔
970

971
    SColumnInfoData* pDstCol = taosArrayGet(pCtx->pDstBlock->pDataBlock, dstSlotId);
521,300✔
972
    if (NULL == pDstCol) {
521,300✔
973
      return TSDB_CODE_OUT_OF_RANGE;
×
974
    }
975

976
    if (colDataIsNull_s(pSrcCol, rowIndex) == true) {
1,042,600✔
977
      colDataSetNULL(pDstCol, pos);
61,208✔
978
    } else {
979
      code = colDataSetVal(pDstCol, pos, pData, false);
460,092✔
980
      if (TSDB_CODE_SUCCESS != code) {
460,092✔
981
        return code;
×
982
      }
983
    }
984
  }
985
  return code;
213,758✔
986
}
987

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

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

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

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

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

1080
int32_t getStdInfoSize() { return (int32_t)sizeof(SStdRes); }
18,774,836✔
1081

1082
bool getStdFuncEnv(SFunctionNode* pFunc, SFuncExecEnv* pEnv) {
1,395,692✔
1083
  pEnv->calcMemSize = sizeof(SStdRes);
1,395,692✔
1084
  return true;
1,396,369✔
1085
}
1086

1087
int32_t stdFunctionSetup(SqlFunctionCtx* pCtx, SResultRowEntryInfo* pResultInfo) {
116,823,638✔
1088
  if (pResultInfo->initialized) {
116,823,638✔
1089
    return TSDB_CODE_SUCCESS;
×
1090
  }
1091
  if (TSDB_CODE_SUCCESS != functionSetup(pCtx, pResultInfo)) {
116,823,638✔
1092
    return TSDB_CODE_FUNC_SETUP_ERROR;
×
1093
  }
1094

1095
  SStdRes* pRes = GET_ROWCELL_INTERBUF(pResultInfo);
116,827,986✔
1096
  (void)memset(pRes, 0, sizeof(SStdRes));
116,827,922✔
1097
  return TSDB_CODE_SUCCESS;
116,827,922✔
1098
}
1099

1100
int32_t stdFunction(SqlFunctionCtx* pCtx) {
100,322,489✔
1101
  int32_t numOfElem = 0;
100,322,489✔
1102

1103
  // Only the pre-computing information loaded and actual data does not loaded
1104
  SInputColumnInfoData* pInput = &pCtx->input;
100,322,489✔
1105
  int32_t               type = pInput->pData[0]->info.type;
100,323,220✔
1106

1107
  SStdRes* pStdRes = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
100,324,658✔
1108
  pStdRes->type = type;
100,324,607✔
1109

1110
  // computing based on the true data block
1111
  SColumnInfoData* pCol = pInput->pData[0];
100,325,007✔
1112

1113
  int32_t start = pInput->startRowIndex;
100,325,607✔
1114
  int32_t numOfRows = pInput->numOfRows;
100,326,649✔
1115

1116
  if (IS_NULL_TYPE(type)) {
100,325,737✔
1117
    numOfElem = 0;
78,687✔
1118
    goto _stddev_over;
78,687✔
1119
  }
1120

1121
  switch (type) {
100,247,050✔
1122
    case TSDB_DATA_TYPE_TINYINT: {
3,112,478✔
1123
      int8_t* plist = (int8_t*)pCol->pData;
3,112,478✔
1124
      for (int32_t i = start; i < numOfRows + start; ++i) {
34,437,724✔
1125
        if (pCol->hasNull && colDataIsNull_f(pCol, i)) {
31,325,246✔
1126
          continue;
8,098,031✔
1127
        }
1128

1129
        numOfElem += 1;
23,227,215✔
1130
        pStdRes->count += 1;
23,227,215✔
1131
        double nr = (double)plist[i];
23,227,215✔
1132
        if (pStdRes->count == 1) {
23,227,215✔
1133
          pStdRes->dsum = nr;
232,080✔
1134
        } else {
1135
          double          s_kminusone = pStdRes->dsum;
22,995,135✔
1136
          volatile double diff = nr - s_kminusone;
22,995,135✔
1137
          pStdRes->dsum = s_kminusone + diff / (double)pStdRes->count;
22,995,135✔
1138
          pStdRes->quadraticDSum += diff * (nr - pStdRes->dsum);
22,995,135✔
1139
        }
1140
      }
1141

1142
      break;
3,112,478✔
1143
    }
1144

1145
    case TSDB_DATA_TYPE_SMALLINT: {
45,025,391✔
1146
      int16_t* plist = (int16_t*)pCol->pData;
45,025,391✔
1147
      for (int32_t i = start; i < numOfRows + pInput->startRowIndex; ++i) {
117,840,927✔
1148
        if (pCol->hasNull && colDataIsNull_f(pCol, i)) {
72,815,536✔
1149
          continue;
7,917,880✔
1150
        }
1151

1152
        numOfElem += 1;
64,897,656✔
1153
        pStdRes->count += 1;
64,897,656✔
1154
        double nr = (double)plist[i];
64,897,656✔
1155
        if (pStdRes->count == 1) {
64,897,656✔
1156
          pStdRes->dsum = nr;
41,778,969✔
1157
        } else {
1158
          double          s_kminusone = pStdRes->dsum;
23,118,687✔
1159
          volatile double diff = nr - s_kminusone;
23,118,687✔
1160
          pStdRes->dsum = s_kminusone + diff / (double)pStdRes->count;
23,118,687✔
1161
          pStdRes->quadraticDSum += diff * (nr - pStdRes->dsum);
23,118,687✔
1162
        }
1163
      }
1164
      break;
45,025,391✔
1165
    }
1166

1167
    case TSDB_DATA_TYPE_INT: {
20,484,704✔
1168
      int32_t* plist = (int32_t*)pCol->pData;
20,484,704✔
1169
      for (int32_t i = start; i < numOfRows + pInput->startRowIndex; ++i) {
2,147,483,647✔
1170
        if (pCol->hasNull && colDataIsNull_f(pCol, i)) {
2,147,483,647✔
1171
          continue;
5,478,314✔
1172
        }
1173

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

1187
      break;
20,485,227✔
1188
    }
1189

1190
    case TSDB_DATA_TYPE_BIGINT: {
3,874,123✔
1191
      int64_t* plist = (int64_t*)pCol->pData;
3,874,123✔
1192
      for (int32_t i = start; i < numOfRows + pInput->startRowIndex; ++i) {
88,487,228✔
1193
        if (pCol->hasNull && colDataIsNull_f(pCol, i)) {
84,617,371✔
1194
          continue;
2,188,488✔
1195
        }
1196

1197
        numOfElem += 1;
82,427,234✔
1198
        pStdRes->count += 1;
82,427,234✔
1199
        double nr = (double)plist[i];
82,427,680✔
1200
        if (pStdRes->count == 1) {
82,427,841✔
1201
          pStdRes->dsum = nr;
3,710,574✔
1202
        } else {
1203
          double          s_kminusone = pStdRes->dsum;
78,719,275✔
1204
          volatile double diff = nr - s_kminusone;
78,719,275✔
1205
          pStdRes->dsum = s_kminusone + diff / (double)pStdRes->count;
78,719,275✔
1206
          pStdRes->quadraticDSum += diff * (nr - pStdRes->dsum);
78,719,275✔
1207
        }
1208
      }
1209
      break;
3,873,751✔
1210
    }
1211

1212
    case TSDB_DATA_TYPE_UTINYINT: {
7,535✔
1213
      uint8_t* plist = (uint8_t*)pCol->pData;
7,535✔
1214
      for (int32_t i = start; i < numOfRows + start; ++i) {
20,738,337✔
1215
        if (pCol->hasNull && colDataIsNull_f(pCol, i)) {
20,730,802✔
1216
          continue;
3,184✔
1217
        }
1218

1219
        numOfElem += 1;
20,727,618✔
1220
        pStdRes->count += 1;
20,727,618✔
1221
        double nr = (double)plist[i];
20,727,618✔
1222
        if (pStdRes->count == 1) {
20,727,618✔
1223
          pStdRes->dsum = nr;
1,837✔
1224
        } else {
1225
          double          s_kminusone = pStdRes->dsum;
20,725,781✔
1226
          volatile double diff = nr - s_kminusone;
20,725,781✔
1227
          pStdRes->dsum = s_kminusone + diff / (double)pStdRes->count;
20,725,781✔
1228
          pStdRes->quadraticDSum += diff * (nr - pStdRes->dsum);
20,725,781✔
1229
        }
1230
      }
1231

1232
      break;
7,535✔
1233
    }
1234

1235
    case TSDB_DATA_TYPE_USMALLINT: {
7,266✔
1236
      uint16_t* plist = (uint16_t*)pCol->pData;
7,266✔
1237
      for (int32_t i = start; i < numOfRows + pInput->startRowIndex; ++i) {
20,798,898✔
1238
        if (pCol->hasNull && colDataIsNull_f(pCol, i)) {
20,791,632✔
1239
          continue;
×
1240
        }
1241

1242
        numOfElem += 1;
20,791,632✔
1243
        pStdRes->count += 1;
20,791,632✔
1244
        double nr = (double)plist[i];
20,791,632✔
1245
        if (pStdRes->count == 1) {
20,791,632✔
1246
          pStdRes->dsum = nr;
1,568✔
1247
        } else {
1248
          double          s_kminusone = pStdRes->dsum;
20,790,064✔
1249
          volatile double diff = nr - s_kminusone;
20,790,064✔
1250
          pStdRes->dsum = s_kminusone + diff / (double)pStdRes->count;
20,790,064✔
1251
          pStdRes->quadraticDSum += diff * (nr - pStdRes->dsum);
20,790,064✔
1252
        }
1253
      }
1254
      break;
7,266✔
1255
    }
1256

1257
    case TSDB_DATA_TYPE_UINT: {
7,223✔
1258
      uint32_t* plist = (uint32_t*)pCol->pData;
7,223✔
1259
      for (int32_t i = start; i < numOfRows + pInput->startRowIndex; ++i) {
20,734,873✔
1260
        if (pCol->hasNull && colDataIsNull_f(pCol, i)) {
20,727,650✔
1261
          continue;
×
1262
        }
1263

1264
        numOfElem += 1;
20,727,650✔
1265
        pStdRes->count += 1;
20,727,650✔
1266
        double nr = (double)plist[i];
20,727,650✔
1267
        if (pStdRes->count == 1) {
20,727,650✔
1268
          pStdRes->dsum = nr;
1,525✔
1269
        } else {
1270
          double          s_kminusone = pStdRes->dsum;
20,726,125✔
1271
          volatile double diff = nr - s_kminusone;
20,726,125✔
1272
          pStdRes->dsum = s_kminusone + diff / (double)pStdRes->count;
20,726,125✔
1273
          pStdRes->quadraticDSum += diff * (nr - pStdRes->dsum);
20,726,125✔
1274
        }
1275
      }
1276

1277
      break;
7,223✔
1278
    }
1279

1280
    case TSDB_DATA_TYPE_UBIGINT: {
6,739✔
1281
      uint64_t* plist = (uint64_t*)pCol->pData;
6,739✔
1282
      for (int32_t i = start; i < numOfRows + pInput->startRowIndex; ++i) {
20,731,969✔
1283
        if (pCol->hasNull && colDataIsNull_f(pCol, i)) {
20,725,230✔
1284
          continue;
×
1285
        }
1286

1287
        numOfElem += 1;
20,725,230✔
1288
        pStdRes->count += 1;
20,725,230✔
1289
        double nr = (double)plist[i];
20,725,230✔
1290
        if (pStdRes->count == 1) {
20,725,230✔
1291
          pStdRes->dsum = nr;
1,041✔
1292
        } else {
1293
          double          s_kminusone = pStdRes->dsum;
20,724,189✔
1294
          volatile double diff = nr - s_kminusone;
20,724,189✔
1295
          pStdRes->dsum = s_kminusone + diff / (double)pStdRes->count;
20,724,189✔
1296
          pStdRes->quadraticDSum += diff * (nr - pStdRes->dsum);
20,724,189✔
1297
        }
1298
      }
1299
      break;
6,739✔
1300
    }
1301

1302
    case TSDB_DATA_TYPE_FLOAT: {
21,122,731✔
1303
      float* plist = (float*)pCol->pData;
21,122,731✔
1304
      for (int32_t i = start; i < numOfRows + pInput->startRowIndex; ++i) {
2,065,521,368✔
1305
        if (pCol->hasNull && colDataIsNull_f(pCol, i)) {
2,044,404,425✔
1306
          continue;
13,105,786✔
1307
        }
1308

1309
        numOfElem += 1;
2,031,295,399✔
1310
        pStdRes->count += 1;
2,031,295,399✔
1311
        double nr = (double)plist[i];
2,031,295,427✔
1312
        if (pStdRes->count == 1) {
2,031,294,503✔
1313
          pStdRes->dsum = nr;
12,138,923✔
1314
        } else {
1315
          double          s_kminusone = pStdRes->dsum;
2,019,157,248✔
1316
          volatile double diff = nr - s_kminusone;
2,019,156,724✔
1317
          pStdRes->dsum = s_kminusone + diff / (double)pStdRes->count;
2,019,156,724✔
1318
          pStdRes->quadraticDSum += diff * (nr - pStdRes->dsum);
2,019,156,724✔
1319
        }
1320
      }
1321
      break;
21,123,255✔
1322
    }
1323

1324
    case TSDB_DATA_TYPE_DOUBLE: {
6,598,860✔
1325
      double* plist = (double*)pCol->pData;
6,598,860✔
1326
      for (int32_t i = start; i < numOfRows + pInput->startRowIndex; ++i) {
112,350,288✔
1327
        if (pCol->hasNull && colDataIsNull_f(pCol, i)) {
105,752,779✔
1328
          continue;
15,307,161✔
1329
        }
1330

1331
        numOfElem += 1;
90,443,252✔
1332
        pStdRes->count += 1;
90,443,252✔
1333
        double nr = (double)plist[i];
90,442,174✔
1334
        if (pStdRes->count == 1) {
90,442,489✔
1335
          pStdRes->dsum = nr;
1,396,047✔
1336
        } else {
1337
          double          s_kminusone = pStdRes->dsum;
89,044,650✔
1338
          volatile double diff = nr - s_kminusone;
89,044,958✔
1339
          pStdRes->dsum = s_kminusone + diff / (double)pStdRes->count;
89,044,958✔
1340
          pStdRes->quadraticDSum += diff * (nr - pStdRes->dsum);
89,035,396✔
1341
        }
1342
      }
1343
      break;
6,599,651✔
1344
    }
1345

1346
    default:
×
1347
      break;
×
1348
  }
1349

1350
_stddev_over:
100,327,203✔
1351
  // data in the check operation are all null, not output
1352
  SET_VAL(GET_RES_INFO(pCtx), numOfElem, 1);
100,327,203✔
1353
  return TSDB_CODE_SUCCESS;
100,315,175✔
1354
}
1355

1356
static void stdTransferInfo(SStdRes* pInput, SStdRes* pOutput) {
18,688,600✔
1357
  if (IS_NULL_TYPE(pInput->type)) {
18,688,600✔
1358
    return;
13,125✔
1359
  }
1360
  pOutput->type = pInput->type;
18,675,475✔
1361
  if (pOutput->count == 0) {
18,675,475✔
1362
    pOutput->quadraticDSum += pInput->quadraticDSum;
18,651,513✔
1363
    pOutput->dsum += pInput->dsum;
18,651,513✔
1364
    pOutput->count = pInput->count;
18,651,513✔
1365
  } else if (pInput->count > 0) {
23,962✔
1366
    double totalCount = pOutput->count + pInput->count;
23,962✔
1367
    double totalSum = pInput->count * pInput->dsum + pOutput->count * pOutput->dsum;
23,962✔
1368
    double mean = totalSum / totalCount;
23,962✔
1369

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

1375
    double diff = pInput->dsum - pOutput->dsum;
23,962✔
1376
    pOutput->quadraticDSum += pInput->quadraticDSum + pInput->count * pOutput->count * (diff * diff) / totalCount;
23,962✔
1377
    pOutput->dsum = mean;
23,962✔
1378
    pOutput->count += pInput->count;
23,962✔
1379
  }
1380
}
1381

1382
int32_t stdFunctionMerge(SqlFunctionCtx* pCtx) {
18,688,228✔
1383
  SInputColumnInfoData* pInput = &pCtx->input;
18,688,228✔
1384
  SColumnInfoData*      pCol = pInput->pData[0];
18,688,228✔
1385

1386
  if (IS_NULL_TYPE(pCol->info.type)) {
18,688,228✔
1387
    SET_VAL(GET_RES_INFO(pCtx), 0, 1);
×
1388
    return TSDB_CODE_SUCCESS;
×
1389
  }
1390

1391
  if (pCol->info.type != TSDB_DATA_TYPE_BINARY) {
18,688,228✔
1392
    return TSDB_CODE_FUNC_FUNTION_PARA_TYPE;
×
1393
  }
1394

1395
  SStdRes* pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
18,688,228✔
1396

1397
  for (int32_t i = pInput->startRowIndex; i < pInput->startRowIndex + pInput->numOfRows; ++i) {
37,376,828✔
1398
    if (colDataIsNull_s(pCol, i)) continue;
37,377,200✔
1399
    char*    data = colDataGetData(pCol, i);
18,688,600✔
1400
    SStdRes* pInputInfo = (SStdRes*)varDataVal(data);
18,688,600✔
1401
    stdTransferInfo(pInputInfo, pInfo);
18,688,600✔
1402
  }
1403

1404
  SET_VAL(GET_RES_INFO(pCtx), 1, 1);
18,688,228✔
1405
  return TSDB_CODE_SUCCESS;
18,688,228✔
1406
}
1407

1408
int32_t stddevFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
76,196,639✔
1409
  SInputColumnInfoData* pInput = &pCtx->input;
76,196,639✔
1410
  SStdRes*              pStddevRes = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
76,196,639✔
1411
  int32_t               type = pStddevRes->type;
76,196,639✔
1412
  double                avg;
1413

1414
  if (pStddevRes->count == 0) {
76,196,639✔
1415
    GET_RES_INFO(pCtx)->numOfRes = 0;
19,480,606✔
1416

1417
    return functionFinalize(pCtx, pBlock);
19,480,606✔
1418
  }
1419

1420
  if (pStddevRes->count == 1) {
56,716,033✔
1421
    pStddevRes->result = 0.0;
44,707,692✔
1422
  } else {
1423
    pStddevRes->result = sqrt(pStddevRes->quadraticDSum / pStddevRes->count);
12,008,341✔
1424
  }
1425

1426
  // check for overflow
1427
  if (isinf(pStddevRes->result) || isnan(pStddevRes->result)) {
56,716,033✔
1428
    GET_RES_INFO(pCtx)->numOfRes = 0;
×
1429
  }
1430

1431
  return functionFinalize(pCtx, pBlock);
56,716,033✔
1432
}
1433

1434
int32_t stdvarFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
7,433,760✔
1435
  SInputColumnInfoData* pInput = &pCtx->input;
7,433,760✔
1436
  SStdRes*              pStdvarRes = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
7,433,760✔
1437
  int32_t               type = pStdvarRes->type;
7,433,760✔
1438
  double                avg;
1439

1440
  if (pStdvarRes->count == 0) {
7,433,760✔
1441
    GET_RES_INFO(pCtx)->numOfRes = 0;
1,066✔
1442
    return functionFinalize(pCtx, pBlock);
1,066✔
1443
  }
1444

1445
  if (pStdvarRes->count == 1) {
7,432,694✔
1446
    pStdvarRes->result = 0.0;
1,066✔
1447
  } else {
1448
    pStdvarRes->result = pStdvarRes->quadraticDSum / pStdvarRes->count;
7,431,628✔
1449
  }
1450

1451
  // check for overflow
1452
  if (isinf(pStdvarRes->result) || isnan(pStdvarRes->result)) {
7,432,694✔
1453
    GET_RES_INFO(pCtx)->numOfRes = 0;
×
1454
  }
1455

1456
  return functionFinalize(pCtx, pBlock);
7,432,694✔
1457
}
1458

1459
int32_t stdPartialFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
18,688,357✔
1460
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
18,688,357✔
1461
  SStdRes*             pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
18,688,357✔
1462
  int32_t              resultBytes = getStdInfoSize();
18,688,357✔
1463
  char*                res = taosMemoryCalloc(resultBytes + VARSTR_HEADER_SIZE, sizeof(char));
18,688,357✔
1464

1465
  if (NULL == res) {
18,688,600✔
1466
    return terrno;
×
1467
  }
1468
  (void)memcpy(varDataVal(res), pInfo, resultBytes);
18,688,600✔
1469
  varDataSetLen(res, resultBytes);
18,688,600✔
1470

1471
  int32_t          slotId = pCtx->pExpr->base.resSchema.slotId;
18,688,600✔
1472
  SColumnInfoData* pCol = taosArrayGet(pBlock->pDataBlock, slotId);
18,688,600✔
1473
  if (NULL == pCol) {
18,688,600✔
1474
    taosMemoryFree(res);
×
1475
    return TSDB_CODE_OUT_OF_RANGE;
×
1476
  }
1477

1478
  int32_t code = colDataSetVal(pCol, pBlock->info.rows, res, false);
18,688,600✔
1479

1480
  taosMemoryFree(res);
18,688,600✔
1481
  return code;
18,688,600✔
1482
}
1483

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

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

1492
  stdTransferInfo(pSBuf, pDBuf);
×
1493

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

1499
int32_t stddevsampFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
3,718,217✔
1500
  SInputColumnInfoData* pInput = &pCtx->input;
3,718,217✔
1501
  SStdRes*              pStddevRes = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
3,718,217✔
1502
  double                avg;
1503

1504
  if (pStddevRes->count == 0) {
3,718,217✔
1505
    GET_RES_INFO(pCtx)->numOfRes = 0;
533✔
1506
    return functionFinalize(pCtx, pBlock);
533✔
1507
  }
1508

1509
  if (pStddevRes->count == 1) {
3,717,684✔
1510
    pStddevRes->result = 0.0;
533✔
1511
  } else {
1512
    pStddevRes->result = sqrt(pStddevRes->quadraticDSum / (pStddevRes->count - 1));
3,717,151✔
1513
  }
1514

1515
  // check for overflow
1516
  if (isinf(pStddevRes->result) || isnan(pStddevRes->result)) {
3,717,684✔
1517
    GET_RES_INFO(pCtx)->numOfRes = 0;
×
1518
  }
1519

1520
  return functionFinalize(pCtx, pBlock);
3,717,684✔
1521
}
1522

1523
int32_t stdvarsampFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
3,717,151✔
1524
  SInputColumnInfoData* pInput = &pCtx->input;
3,717,151✔
1525
  SStdRes*              pStddevRes = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
3,717,151✔
1526
  double                avg;
1527

1528
  if (pStddevRes->count == 0) {
3,717,151✔
1529
    GET_RES_INFO(pCtx)->numOfRes = 0;
533✔
1530
    return functionFinalize(pCtx, pBlock);
533✔
1531
  }
1532

1533
  if (pStddevRes->count == 1) {
3,716,618✔
1534
    pStddevRes->result = 0.0;
533✔
1535
  } else {
1536
    pStddevRes->result = pStddevRes->quadraticDSum / (pStddevRes->count - 1);
3,716,085✔
1537
  }
1538

1539
  // check for overflow
1540
  if (isinf(pStddevRes->result) || isnan(pStddevRes->result)) {
3,716,618✔
1541
    GET_RES_INFO(pCtx)->numOfRes = 0;
×
1542
  }
1543

1544
  return functionFinalize(pCtx, pBlock);
3,716,618✔
1545
}
1546

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

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

1560
  SGconcatRes* pRes = GET_ROWCELL_INTERBUF(pResultInfo);
1,086✔
1561
  (void)memset(pRes, 0, sizeof(SStdRes));
1,086✔
1562

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

1565
  int32_t sepParamIdx = pCtx->numOfParams - 1;
1,086✔
1566
  pRes->separator = pCtx->param[sepParamIdx].param.pz;
1,086✔
1567
  pRes->type = pCtx->param[sepParamIdx].param.nType;
1,086✔
1568

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

1573
  pRes->nchar = (type == TSDB_DATA_TYPE_NCHAR);
1574
  */
1575

1576
  return TSDB_CODE_SUCCESS;
1,086✔
1577
}
1578

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

1601
  return TSDB_CODE_SUCCESS;
20,634✔
1602
}
1603

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

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

1622
    varDataSetLen(pRes->result, 0);
1,086✔
1623

1624
    for (int c = 0; c < numOfCols - 1; ++c) {
2,172✔
1625
      SColumnInfoData* pCol = pInput->pData[c];
1,086✔
1626
      int32_t          type = pCol->info.type;
1,086✔
1627

1628
      if (TSDB_DATA_TYPE_NCHAR == type) {
1,086✔
1629
        pRes->nchar = true;
×
1630
      }
1631
    }
1632
  } else {
1633
    dataLen = varDataLen(pRes->result);
×
1634

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

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

1648
  sep = colDataGetData(pCol, 0);
1,086✔
1649
  pRes->type = pCol->info.type;
1,086✔
1650
  for (int r = rowStart; r < rowStart + numOfRows; ++r) {
11,946✔
1651
    if (prefixSep) {
10,860✔
1652
      // concat the separator
1653
      // setup sepatator's charset instead of the default: pRes->charsetCxt
1654

1655
      code = gconcatHelper(sep, buf, hasNchar, pRes->type, &dataLen, NULL);
9,774✔
1656
      if (code) {
9,774✔
1657
        goto _over;
×
1658
      }
1659
    }
1660

1661
    for (int c = 0; c < numOfCols - 1; ++c) {
21,720✔
1662
      SColumnInfoData* pCol = pInput->pData[c];
10,860✔
1663
      int32_t          type = pCol->info.type;
10,860✔
1664

1665
      if (IS_NULL_TYPE(type) || (pCol->hasNull && colDataIsNull_f(pCol, r))) {
10,860✔
1666
        continue;
×
1667
      }
1668

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

1676
    prefixSep = true;
10,860✔
1677
  }
1678

1679
  varDataSetLen(buf, dataLen);
1,086✔
1680
  numOfElem += 1;
1,086✔
1681

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

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

1695
  if (NULL == pCol) {
1,086✔
1696
    taosMemoryFree(pRes->result);
×
1697
    return TSDB_CODE_OUT_OF_RANGE;
×
1698
  }
1699

1700
  code = colDataSetVal(pCol, pBlock->info.rows, pRes->result, NULL == pRes->result);
1,086✔
1701

1702
  taosMemoryFree(pRes->result);
1,086✔
1703

1704
  return code;
1,086✔
1705
}
1706

1707
bool getLeastSQRFuncEnv(SFunctionNode* pFunc, SFuncExecEnv* pEnv) {
377,181✔
1708
  pEnv->calcMemSize = sizeof(SLeastSQRInfo);
377,181✔
1709
  return true;
377,181✔
1710
}
1711

1712
int32_t leastSQRFunctionSetup(SqlFunctionCtx* pCtx, SResultRowEntryInfo* pResultInfo) {
1,707,272✔
1713
  if (pResultInfo->initialized) {
1,707,272✔
1714
    return TSDB_CODE_SUCCESS;
×
1715
  }
1716
  if (TSDB_CODE_SUCCESS != functionSetup(pCtx, pResultInfo)) {
1,707,272✔
1717
    return TSDB_CODE_FUNC_SETUP_ERROR;
×
1718
  }
1719

1720
  SLeastSQRInfo* pInfo = GET_ROWCELL_INTERBUF(pResultInfo);
1,707,594✔
1721

1722
  GET_TYPED_DATA(pInfo->startVal, double, pCtx->param[1].param.nType, &pCtx->param[1].param.i,
1,707,594✔
1723
                 typeGetTypeModFromCol(pCtx->param[1].pCol));
1724
  GET_TYPED_DATA(pInfo->stepVal, double, pCtx->param[2].param.nType, &pCtx->param[2].param.i,
1,707,272✔
1725
                 typeGetTypeModFromCol(pCtx->param[2].pCol));
1726
  return TSDB_CODE_SUCCESS;
1,707,272✔
1727
}
1728

1729
int32_t leastSQRFunction(SqlFunctionCtx* pCtx) {
2,601,366✔
1730
  int32_t numOfElem = 0;
2,601,366✔
1731

1732
  SInputColumnInfoData* pInput = &pCtx->input;
2,601,366✔
1733
  int32_t               type = pInput->pData[0]->info.type;
2,601,527✔
1734

1735
  SLeastSQRInfo* pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
2,601,527✔
1736

1737
  SColumnInfoData* pCol = pInput->pData[0];
2,601,366✔
1738

1739
  double(*param)[3] = pInfo->matrix;
2,601,205✔
1740
  double x = pInfo->startVal;
2,601,205✔
1741

1742
  int32_t start = pInput->startRowIndex;
2,601,205✔
1743
  int32_t numOfRows = pInput->numOfRows;
2,601,205✔
1744

1745
  switch (type) {
2,601,205✔
1746
    case TSDB_DATA_TYPE_TINYINT: {
127,395✔
1747
      int8_t* plist = (int8_t*)pCol->pData;
127,395✔
1748
      for (int32_t i = start; i < numOfRows + pInput->startRowIndex; ++i) {
21,077,349✔
1749
        if (pCol->hasNull && colDataIsNull_f(pCol, i)) {
20,949,954✔
1750
          continue;
39,236✔
1751
        }
1752
        numOfElem++;
20,910,718✔
1753
        LEASTSQR_CAL(param, x, plist, i, pInfo->stepVal);
20,910,718✔
1754
      }
1755
      break;
127,395✔
1756
    }
1757
    case TSDB_DATA_TYPE_SMALLINT: {
126,744✔
1758
      int16_t* plist = (int16_t*)pCol->pData;
126,744✔
1759
      for (int32_t i = start; i < numOfRows + pInput->startRowIndex; ++i) {
20,997,896✔
1760
        if (pCol->hasNull && colDataIsNull_f(pCol, i)) {
20,871,152✔
1761
          continue;
26,836✔
1762
        }
1763

1764
        numOfElem++;
20,844,316✔
1765
        LEASTSQR_CAL(param, x, plist, i, pInfo->stepVal);
20,844,316✔
1766
      }
1767
      break;
126,744✔
1768
    }
1769

1770
    case TSDB_DATA_TYPE_INT: {
159,174✔
1771
      int32_t* plist = (int32_t*)pCol->pData;
159,174✔
1772
      for (int32_t i = start; i < numOfRows + pInput->startRowIndex; ++i) {
27,412,036✔
1773
        if (pCol->hasNull && colDataIsNull_f(pCol, i)) {
27,252,862✔
1774
          continue;
86,723✔
1775
        }
1776

1777
        numOfElem++;
27,166,139✔
1778
        LEASTSQR_CAL(param, x, plist, i, pInfo->stepVal);
27,166,139✔
1779
      }
1780
      break;
159,174✔
1781
    }
1782

1783
    case TSDB_DATA_TYPE_BIGINT: {
1,039,437✔
1784
      int64_t* plist = (int64_t*)pCol->pData;
1,039,437✔
1785
      for (int32_t i = start; i < numOfRows + pInput->startRowIndex; ++i) {
66,845,027✔
1786
        if (pCol->hasNull && colDataIsNull_f(pCol, i)) {
65,804,946✔
1787
          continue;
67,836✔
1788
        }
1789

1790
        numOfElem++;
65,736,788✔
1791
        LEASTSQR_CAL(param, x, plist, i, pInfo->stepVal);
65,736,788✔
1792
      }
1793
      break;
1,039,759✔
1794
    }
1795

1796
    case TSDB_DATA_TYPE_UTINYINT: {
19,944✔
1797
      uint8_t* plist = (uint8_t*)pCol->pData;
19,944✔
1798
      for (int32_t i = start; i < numOfRows + pInput->startRowIndex; ++i) {
20,784,296✔
1799
        if (pCol->hasNull && colDataIsNull_f(pCol, i)) {
20,764,352✔
1800
          continue;
11,616✔
1801
        }
1802
        numOfElem++;
20,752,736✔
1803
        LEASTSQR_CAL(param, x, plist, i, pInfo->stepVal);
20,752,736✔
1804
      }
1805
      break;
19,944✔
1806
    }
1807
    case TSDB_DATA_TYPE_USMALLINT: {
19,944✔
1808
      uint16_t* plist = (uint16_t*)pCol->pData;
19,944✔
1809
      for (int32_t i = start; i < numOfRows + pInput->startRowIndex; ++i) {
20,784,296✔
1810
        if (pCol->hasNull && colDataIsNull_f(pCol, i)) {
20,764,352✔
1811
          continue;
10,560✔
1812
        }
1813

1814
        numOfElem++;
20,753,792✔
1815
        LEASTSQR_CAL(param, x, plist, i, pInfo->stepVal);
20,753,792✔
1816
      }
1817
      break;
19,944✔
1818
    }
1819

1820
    case TSDB_DATA_TYPE_UINT: {
19,944✔
1821
      uint32_t* plist = (uint32_t*)pCol->pData;
19,944✔
1822
      for (int32_t i = start; i < numOfRows + pInput->startRowIndex; ++i) {
20,784,296✔
1823
        if (pCol->hasNull && colDataIsNull_f(pCol, i)) {
20,764,352✔
1824
          continue;
10,560✔
1825
        }
1826

1827
        numOfElem++;
20,753,792✔
1828
        LEASTSQR_CAL(param, x, plist, i, pInfo->stepVal);
20,753,792✔
1829
      }
1830
      break;
19,944✔
1831
    }
1832

1833
    case TSDB_DATA_TYPE_UBIGINT: {
19,944✔
1834
      uint64_t* plist = (uint64_t*)pCol->pData;
19,944✔
1835
      for (int32_t i = start; i < numOfRows + pInput->startRowIndex; ++i) {
20,784,296✔
1836
        if (pCol->hasNull && colDataIsNull_f(pCol, i)) {
20,764,352✔
1837
          continue;
10,560✔
1838
        }
1839

1840
        numOfElem++;
20,753,792✔
1841
        LEASTSQR_CAL(param, x, plist, i, pInfo->stepVal);
20,753,792✔
1842
      }
1843
      break;
19,944✔
1844
    }
1845

1846
    case TSDB_DATA_TYPE_FLOAT: {
779,168✔
1847
      float* plist = (float*)pCol->pData;
779,168✔
1848
      for (int32_t i = start; i < numOfRows + pInput->startRowIndex; ++i) {
22,315,020✔
1849
        if (pCol->hasNull && colDataIsNull_f(pCol, i)) {
21,535,852✔
1850
          continue;
84,536✔
1851
        }
1852

1853
        numOfElem++;
21,451,316✔
1854
        LEASTSQR_CAL(param, x, plist, i, pInfo->stepVal);
21,451,316✔
1855
      }
1856
      break;
779,168✔
1857
    }
1858

1859
    case TSDB_DATA_TYPE_DOUBLE: {
289,511✔
1860
      double* plist = (double*)pCol->pData;
289,511✔
1861
      for (int32_t i = start; i < numOfRows + pInput->startRowIndex; ++i) {
21,779,827✔
1862
        if (pCol->hasNull && colDataIsNull_f(pCol, i)) {
21,490,316✔
1863
          continue;
84,536✔
1864
        }
1865

1866
        numOfElem++;
21,405,780✔
1867
        LEASTSQR_CAL(param, x, plist, i, pInfo->stepVal);
21,405,780✔
1868
      }
1869
      break;
289,511✔
1870
    }
1871
    case TSDB_DATA_TYPE_NULL: {
×
1872
      GET_RES_INFO(pCtx)->isNullRes = 1;
×
1873
      numOfElem = 1;
×
1874
      break;
×
1875
    }
1876

1877
    default:
×
1878
      break;
×
1879
  }
1880

1881
  pInfo->startVal = x;
2,601,527✔
1882
  pInfo->num += numOfElem;
2,601,527✔
1883

1884
  SET_VAL(GET_RES_INFO(pCtx), numOfElem, 1);
2,601,527✔
1885

1886
  return TSDB_CODE_SUCCESS;
2,601,527✔
1887
}
1888

1889
int32_t leastSQRFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
1,706,540✔
1890
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
1,706,540✔
1891
  SLeastSQRInfo*       pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
1,706,540✔
1892
  int32_t              slotId = pCtx->pExpr->base.resSchema.slotId;
1,706,540✔
1893
  SColumnInfoData*     pCol = taosArrayGet(pBlock->pDataBlock, slotId);
1,706,540✔
1894

1895
  if (NULL == pCol) {
1,706,540✔
1896
    return TSDB_CODE_OUT_OF_RANGE;
×
1897
  }
1898
  int32_t currentRow = pBlock->info.rows;
1,706,540✔
1899

1900
  if (0 == pInfo->num) {
1,706,540✔
1901
    colDataSetNULL(pCol, currentRow);
295,189✔
1902
    return TSDB_CODE_SUCCESS;
295,189✔
1903
  }
1904

1905
  double(*param)[3] = pInfo->matrix;
1,411,351✔
1906

1907
  param[1][1] = (double)pInfo->num;
1,411,351✔
1908
  param[1][0] = param[0][1];
1,411,351✔
1909

1910
  double param00 = param[0][0] - param[1][0] * (param[0][1] / param[1][1]);
1,411,351✔
1911
  double param02 = param[0][2] - param[1][2] * (param[0][1] / param[1][1]);
1,411,351✔
1912

1913
  if (0 == param00) {
1,411,190✔
1914
    colDataSetNULL(pCol, currentRow);
986,204✔
1915
    return TSDB_CODE_SUCCESS;
986,365✔
1916
  }
1917

1918
  // param[0][1] = 0;
1919
  double param12 = param[1][2] - param02 * (param[1][0] / param00);
424,986✔
1920
  // param[1][0] = 0;
1921
  param02 /= param00;
424,986✔
1922

1923
  param12 /= param[1][1];
424,986✔
1924

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

1940
  int32_t code = colDataSetVal(pCol, currentRow, buf, pResInfo->isNullRes);
424,986✔
1941

1942
  return code;
424,986✔
1943
}
1944

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

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

1967
bool getPercentileFuncEnv(SFunctionNode* pFunc, SFuncExecEnv* pEnv) {
99,204✔
1968
  pEnv->calcMemSize = sizeof(SPercentileInfo);
99,204✔
1969
  return true;
99,204✔
1970
}
1971

1972
int32_t percentileFunctionSetup(SqlFunctionCtx* pCtx, SResultRowEntryInfo* pResultInfo) {
203,683✔
1973
  if (pResultInfo->initialized) {
203,683✔
1974
    return TSDB_CODE_SUCCESS;
×
1975
  }
1976
  if (TSDB_CODE_SUCCESS != functionSetup(pCtx, pResultInfo)) {
203,683✔
1977
    return TSDB_CODE_FUNC_SETUP_ERROR;
×
1978
  }
1979

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

1986
  return TSDB_CODE_SUCCESS;
203,683✔
1987
}
1988

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

2000
int32_t percentileFunction(SqlFunctionCtx* pCtx) {
1,512,146✔
2001
  int32_t              code = TSDB_CODE_SUCCESS;
1,512,146✔
2002
  int32_t              numOfElems = 0;
1,512,146✔
2003
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
1,512,146✔
2004

2005
  SInputColumnInfoData* pInput = &pCtx->input;
1,512,146✔
2006
  SColumnDataAgg*       pAgg = pInput->pColumnDataAgg[0];
1,512,146✔
2007

2008
  SColumnInfoData* pCol = pInput->pData[0];
1,512,146✔
2009
  int32_t          type = pCol->info.type;
1,512,146✔
2010

2011
  SPercentileInfo* pInfo = GET_ROWCELL_INTERBUF(pResInfo);
1,512,146✔
2012
  if (pCtx->scanFlag == MAIN_SCAN && pInfo->stage == 0) {
1,512,146✔
2013
    pInfo->stage += 1;
203,683✔
2014

2015
    // all data are null, set it completed
2016
    if (pInfo->numOfElems == 0) {
203,683✔
2017
      pResInfo->complete = true;
20,705✔
2018
      return TSDB_CODE_SUCCESS;
20,705✔
2019
    } else {
2020
      code = tMemBucketCreate(pCol->info.bytes, type, typeGetTypeModFromColInfo(&pCol->info), pInfo->minval,
182,978✔
2021
                              pInfo->maxval, pCtx->hasWindowOrGroup, &pInfo->pMemBucket, pInfo->numOfElems);
182,978✔
2022
      if (TSDB_CODE_SUCCESS != code) {
182,978✔
2023
        return code;
×
2024
      }
2025
    }
2026
  }
2027

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

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

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

2051
      pInfo->numOfElems += (pInput->numOfRows - pAgg->numOfNull);
×
2052
    } else {
2053
      // check the valid data one by one
2054
      int32_t start = pInput->startRowIndex;
756,073✔
2055
      for (int32_t i = start; i < pInput->numOfRows + start; ++i) {
18,648,916✔
2056
        if (colDataIsNull_f(pCol, i)) {
17,892,843✔
2057
          continue;
75,782✔
2058
        }
2059

2060
        char* data = colDataGetData(pCol, i);
17,817,061✔
2061

2062
        double v = 0;
17,817,061✔
2063
        GET_TYPED_DATA(v, double, type, data, typeGetTypeModFromColInfo(&pCol->info));
17,817,061✔
2064
        if (v < GET_DOUBLE_VAL(&pInfo->minval)) {
17,817,061✔
2065
          SET_DOUBLE_VAL(&pInfo->minval, v);
215,315✔
2066
        }
2067

2068
        if (v > GET_DOUBLE_VAL(&pInfo->maxval)) {
17,817,061✔
2069
          SET_DOUBLE_VAL(&pInfo->maxval, v);
14,222,048✔
2070
        }
2071

2072
        pInfo->numOfElems += 1;
17,817,061✔
2073
      }
2074
    }
2075
  } else {
2076
    // the second stage, calculate the true percentile value
2077
    int32_t start = pInput->startRowIndex;
735,368✔
2078
    for (int32_t i = start; i < pInput->numOfRows + start; ++i) {
18,520,809✔
2079
      if (colDataIsNull_f(pCol, i)) {
17,785,968✔
2080
        continue;
×
2081
      }
2082

2083
      char* data = colDataGetData(pCol, i);
17,785,968✔
2084
      numOfElems += 1;
17,785,968✔
2085
      code = tMemBucketPut(pInfo->pMemBucket, data, 1);
17,785,968✔
2086
      if (code != TSDB_CODE_SUCCESS) {
17,785,968✔
2087
        tMemBucketDestroy(&(pInfo->pMemBucket));
527✔
2088
        return code;
527✔
2089
      }
2090
    }
2091

2092
    SET_VAL(pResInfo, numOfElems, 1);
734,841✔
2093
  }
2094

2095
  pCtx->needCleanup = true;
1,490,914✔
2096
  return TSDB_CODE_SUCCESS;
1,490,914✔
2097
}
2098

2099
int32_t percentileFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
202,629✔
2100
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
202,629✔
2101
  SPercentileInfo*     ppInfo = (SPercentileInfo*)GET_ROWCELL_INTERBUF(pResInfo);
202,629✔
2102

2103
  int32_t code = 0;
202,629✔
2104
  double  v = 0;
202,629✔
2105

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

2114
      varDataVal(buf)[0] = '[';
3,162✔
2115
      for (int32_t i = 1; i < pCtx->numOfParams; ++i) {
34,782✔
2116
        SVariant* pVal = &pCtx->param[i].param;
31,620✔
2117

2118
        GET_TYPED_DATA(v, double, pVal->nType, &pVal->i, typeGetTypeModFromCol(pCtx->param[i].pCol));
31,620✔
2119

2120
        code = getPercentile((*pMemBucket), v, &ppInfo->result);
31,620✔
2121
        if (code != TSDB_CODE_SUCCESS) {
31,620✔
2122
          goto _fin_error;
×
2123
        }
2124

2125
        if (i == pCtx->numOfParams - 1) {
31,620✔
2126
          len += tsnprintf(varDataVal(buf) + len, sizeof(buf) - VARSTR_HEADER_SIZE - len, "%.6lf]", ppInfo->result);
3,162✔
2127
        } else {
2128
          len += tsnprintf(varDataVal(buf) + len, sizeof(buf) - VARSTR_HEADER_SIZE - len, "%.6lf, ", ppInfo->result);
28,458✔
2129
        }
2130
      }
2131

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

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

2145
      tMemBucketDestroy(pMemBucket);
3,162✔
2146
      return TSDB_CODE_SUCCESS;
3,162✔
2147
    } else {
2148
      SVariant* pVal = &pCtx->param[1].param;
178,762✔
2149

2150
      GET_TYPED_DATA(v, double, pVal->nType, &pVal->i, typeGetTypeModFromCol(pCtx->param[1].pCol));
178,762✔
2151

2152
      code = getPercentile((*pMemBucket), v, &ppInfo->result);
178,762✔
2153
      if (code != TSDB_CODE_SUCCESS) {
178,762✔
2154
        goto _fin_error;
×
2155
      }
2156

2157
      tMemBucketDestroy(pMemBucket);
178,762✔
2158
      return functionFinalize(pCtx, pBlock);
178,762✔
2159
    }
2160
  } else {
2161
    return functionFinalize(pCtx, pBlock);
20,705✔
2162
  }
2163

2164
_fin_error:
×
2165

2166
  tMemBucketDestroy(pMemBucket);
×
2167
  return code;
×
2168
}
2169

2170
bool getApercentileFuncEnv(SFunctionNode* pFunc, SFuncExecEnv* pEnv) {
1,312,015✔
2171
  int32_t bytesHist =
1,312,015✔
2172
      (int32_t)(sizeof(SAPercentileInfo) + sizeof(SHistogramInfo) + sizeof(SHistBin) * (MAX_HISTOGRAM_BIN + 1));
2173
  int32_t bytesDigest = (int32_t)(sizeof(SAPercentileInfo) + TDIGEST_SIZE(COMPRESSION));
1,312,015✔
2174
  pEnv->calcMemSize = TMAX(bytesHist, bytesDigest);
1,312,015✔
2175
  return true;
1,313,171✔
2176
}
2177

2178
int32_t getApercentileMaxSize() {
148,044✔
2179
  int32_t bytesHist =
148,044✔
2180
      (int32_t)(sizeof(SAPercentileInfo) + sizeof(SHistogramInfo) + sizeof(SHistBin) * (MAX_HISTOGRAM_BIN + 1));
2181
  int32_t bytesDigest = (int32_t)(sizeof(SAPercentileInfo) + TDIGEST_SIZE(COMPRESSION));
148,044✔
2182
  return TMAX(bytesHist, bytesDigest);
148,044✔
2183
}
2184

2185
static int8_t getApercentileAlgo(char* algoStr) {
1,019,201✔
2186
  int8_t algoType;
2187
  if (strcasecmp(algoStr, "default") == 0) {
1,019,201✔
2188
    algoType = APERCT_ALGO_DEFAULT;
507,594✔
2189
  } else if (strcasecmp(algoStr, "t-digest") == 0) {
511,607✔
2190
    algoType = APERCT_ALGO_TDIGEST;
511,607✔
2191
  } else {
2192
    algoType = APERCT_ALGO_UNKNOWN;
×
2193
  }
2194

2195
  return algoType;
1,019,201✔
2196
}
2197

2198
static void buildHistogramInfo(SAPercentileInfo* pInfo) {
79,823,562✔
2199
  pInfo->pHisto = (SHistogramInfo*)((char*)pInfo + sizeof(SAPercentileInfo));
79,823,562✔
2200
  pInfo->pHisto->elems = (SHistBin*)((char*)pInfo->pHisto + sizeof(SHistogramInfo));
79,824,898✔
2201
}
79,824,374✔
2202

2203
static void buildTDigestInfo(SAPercentileInfo* pInfo) {
1,038,144✔
2204
  pInfo->pTDigest = (TDigest*)((char*)pInfo + sizeof(SAPercentileInfo));
1,038,144✔
2205
}
1,038,144✔
2206

2207
int32_t apercentileFunctionSetup(SqlFunctionCtx* pCtx, SResultRowEntryInfo* pResultInfo) {
27,329,173✔
2208
  if (pResultInfo->initialized) {
27,329,173✔
2209
    return TSDB_CODE_SUCCESS;
×
2210
  }
2211
  if (TSDB_CODE_SUCCESS != functionSetup(pCtx, pResultInfo)) {
27,329,173✔
2212
    return TSDB_CODE_FUNC_SETUP_ERROR;
×
2213
  }
2214

2215
  SAPercentileInfo* pInfo = GET_ROWCELL_INTERBUF(pResultInfo);
27,328,649✔
2216

2217
  SVariant* pVal = &pCtx->param[1].param;
27,328,649✔
2218
  pInfo->percent = 0;
27,328,649✔
2219
  GET_TYPED_DATA(pInfo->percent, double, pVal->nType, &pVal->i, typeGetTypeModFromCol(pCtx->param[1].pCol));
27,328,488✔
2220

2221
  if (pCtx->numOfParams == 2) {
27,329,012✔
2222
    pInfo->algo = APERCT_ALGO_DEFAULT;
26,309,972✔
2223
  } else if (pCtx->numOfParams == 3) {
1,019,201✔
2224
    pInfo->algo = getApercentileAlgo(varDataVal(pCtx->param[2].param.pz));
1,019,201✔
2225
    if (pInfo->algo == APERCT_ALGO_UNKNOWN) {
1,019,201✔
2226
      return TSDB_CODE_FUNC_FUNTION_PARA_VALUE;
×
2227
    }
2228
  }
2229

2230
  char* tmp = (char*)pInfo + sizeof(SAPercentileInfo);
27,328,649✔
2231
  if (pInfo->algo == APERCT_ALGO_TDIGEST) {
27,329,012✔
2232
    pInfo->pTDigest = tdigestNewFrom(tmp, COMPRESSION);
511,446✔
2233
  } else {
2234
    buildHistogramInfo(pInfo);
26,817,566✔
2235
    pInfo->pHisto = tHistogramCreateFrom(tmp, MAX_HISTOGRAM_BIN);
26,816,518✔
2236
    qDebug("%s set up histogram, numOfElems:%" PRId64 ", numOfEntry:%d, pHisto:%p, elems:%p", __FUNCTION__,
26,817,566✔
2237
           pInfo->pHisto->numOfElems, pInfo->pHisto->numOfEntries, pInfo->pHisto, pInfo->pHisto->elems);
2238
  }
2239

2240
  return TSDB_CODE_SUCCESS;
27,329,173✔
2241
}
2242

2243
int32_t apercentileFunction(SqlFunctionCtx* pCtx) {
27,529,503✔
2244
  int32_t               numOfElems = 0;
27,529,503✔
2245
  SResultRowEntryInfo*  pResInfo = GET_RES_INFO(pCtx);
27,529,503✔
2246
  SInputColumnInfoData* pInput = &pCtx->input;
27,529,503✔
2247

2248
  SColumnInfoData* pCol = pInput->pData[0];
27,529,503✔
2249
  int32_t          type = pCol->info.type;
27,529,503✔
2250

2251
  SAPercentileInfo* pInfo = GET_ROWCELL_INTERBUF(pResInfo);
27,528,455✔
2252

2253
  int32_t start = pInput->startRowIndex;
27,528,455✔
2254
  if (pInfo->algo == APERCT_ALGO_TDIGEST) {
27,528,979✔
2255
    buildTDigestInfo(pInfo);
511,074✔
2256
    tdigestAutoFill(pInfo->pTDigest, COMPRESSION);
511,074✔
2257
    for (int32_t i = start; i < pInput->numOfRows + start; ++i) {
23,784,060✔
2258
      if (colDataIsNull_f(pCol, i)) {
23,273,147✔
2259
        continue;
1,985✔
2260
      }
2261
      numOfElems += 1;
23,270,840✔
2262
      char* data = colDataGetData(pCol, i);
23,270,840✔
2263

2264
      double  v = 0;  // value
23,271,645✔
2265
      int64_t w = 1;  // weigth
23,271,645✔
2266
      GET_TYPED_DATA(v, double, type, data, typeGetTypeModFromColInfo(&pCol->info));
23,271,645✔
2267
      int32_t code = tdigestAdd(pInfo->pTDigest, v, w);
23,271,645✔
2268
      if (code != TSDB_CODE_SUCCESS) {
23,271,001✔
2269
        return code;
×
2270
      }
2271
    }
2272
  } else {
2273
    // might be a race condition here that pHisto can be overwritten or setup function
2274
    // has not been called, need to relink the buffer pHisto points to.
2275
    buildHistogramInfo(pInfo);
27,018,429✔
2276
    qDebug("%s before add %d elements into histogram, total:%" PRId64 ", numOfEntry:%d, pHisto:%p, elems: %p",
27,017,381✔
2277
           __FUNCTION__, numOfElems, pInfo->pHisto->numOfElems, pInfo->pHisto->numOfEntries, pInfo->pHisto,
2278
           pInfo->pHisto->elems);
2279
    for (int32_t i = start; i < pInput->numOfRows + start; ++i) {
176,073,717✔
2280
      if (colDataIsNull_f(pCol, i)) {
149,264,868✔
2281
        continue;
20,112,553✔
2282
      }
2283
      numOfElems += 1;
129,079,357✔
2284
      char* data = colDataGetData(pCol, i);
129,079,357✔
2285

2286
      double v = 0;
129,213,643✔
2287
      GET_TYPED_DATA(v, double, type, data, typeGetTypeModFromColInfo(&pCol->info));
129,213,643✔
2288
      int32_t code = tHistogramAdd(&pInfo->pHisto, v);
129,210,635✔
2289
      if (code != TSDB_CODE_SUCCESS) {
128,942,735✔
2290
        return code;
×
2291
      }
2292
    }
2293

2294
    qDebug("%s after add %d elements into histogram, total:%" PRId64 ", numOfEntry:%d, pHisto:%p, elems: %p",
27,018,429✔
2295
           __FUNCTION__, numOfElems, pInfo->pHisto->numOfElems, pInfo->pHisto->numOfEntries, pInfo->pHisto,
2296
           pInfo->pHisto->elems);
2297
  }
2298

2299
  SET_VAL(pResInfo, numOfElems, 1);
27,529,057✔
2300
  return TSDB_CODE_SUCCESS;
27,529,342✔
2301
}
2302

2303
static int32_t apercentileTransferInfo(SAPercentileInfo* pInput, SAPercentileInfo* pOutput, bool* hasRes) {
91,356✔
2304
  pOutput->percent = pInput->percent;
91,356✔
2305
  pOutput->algo = pInput->algo;
91,356✔
2306
  if (pOutput->algo == APERCT_ALGO_TDIGEST) {
91,356✔
2307
    buildTDigestInfo(pInput);
16,523✔
2308
    tdigestAutoFill(pInput->pTDigest, COMPRESSION);
16,523✔
2309

2310
    if (pInput->pTDigest->num_centroids == 0 && pInput->pTDigest->num_buffered_pts == 0) {
16,523✔
2311
      return TSDB_CODE_SUCCESS;
533✔
2312
    }
2313

2314
    if (hasRes) {
15,990✔
2315
      *hasRes = true;
15,990✔
2316
    }
2317

2318
    buildTDigestInfo(pOutput);
15,990✔
2319
    TDigest* pTDigest = pOutput->pTDigest;
15,990✔
2320
    tdigestAutoFill(pTDigest, COMPRESSION);
15,990✔
2321

2322
    if (pTDigest->num_centroids <= 0 && pTDigest->num_buffered_pts == 0) {
15,990✔
2323
      (void)memcpy(pTDigest, pInput->pTDigest, (size_t)TDIGEST_SIZE(COMPRESSION));
15,990✔
2324
      tdigestAutoFill(pTDigest, COMPRESSION);
15,990✔
2325
    } else {
2326
      int32_t code = tdigestMerge(pTDigest, pInput->pTDigest);
×
2327
      if (TSDB_CODE_SUCCESS != code) {
×
2328
        return code;
×
2329
      }
2330
    }
2331
  } else {
2332
    buildHistogramInfo(pInput);
74,833✔
2333
    if (pInput->pHisto->numOfElems <= 0) {
74,833✔
2334
      return TSDB_CODE_SUCCESS;
3,573✔
2335
    }
2336

2337
    if (hasRes) {
71,260✔
2338
      *hasRes = true;
71,260✔
2339
    }
2340

2341
    buildHistogramInfo(pOutput);
71,260✔
2342
    SHistogramInfo* pHisto = pOutput->pHisto;
71,260✔
2343

2344
    if (pHisto->numOfElems <= 0) {
71,260✔
2345
      (void)memcpy(pHisto, pInput->pHisto, sizeof(SHistogramInfo) + sizeof(SHistBin) * (MAX_HISTOGRAM_BIN + 1));
58,001✔
2346
      pHisto->elems = (SHistBin*)((char*)pHisto + sizeof(SHistogramInfo));
58,001✔
2347

2348
      qDebug("%s merge histo, total:%" PRId64 ", entry:%d, %p", __FUNCTION__, pHisto->numOfElems, pHisto->numOfEntries,
58,001✔
2349
             pHisto);
2350
    } else {
2351
      pHisto->elems = (SHistBin*)((char*)pHisto + sizeof(SHistogramInfo));
13,259✔
2352
      qDebug("%s input histogram, elem:%" PRId64 ", entry:%d, %p", __FUNCTION__, pHisto->numOfElems,
13,259✔
2353
             pHisto->numOfEntries, pInput->pHisto);
2354

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

2364
      qDebug("%s merge histo, total:%" PRId64 ", entry:%d, %p", __FUNCTION__, pHisto->numOfElems, pHisto->numOfEntries,
13,259✔
2365
             pHisto);
2366
      tHistogramDestroy(&pRes);
13,259✔
2367
    }
2368
  }
2369
  return TSDB_CODE_SUCCESS;
87,250✔
2370
}
2371

2372
int32_t apercentileFunctionMerge(SqlFunctionCtx* pCtx) {
88,772✔
2373
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
88,772✔
2374

2375
  SInputColumnInfoData* pInput = &pCtx->input;
88,772✔
2376

2377
  SColumnInfoData* pCol = pInput->pData[0];
88,772✔
2378
  if (pCol->info.type != TSDB_DATA_TYPE_BINARY) {
88,772✔
2379
    return TSDB_CODE_FUNC_FUNTION_PARA_TYPE;
×
2380
  }
2381

2382
  SAPercentileInfo* pInfo = GET_ROWCELL_INTERBUF(pResInfo);
88,772✔
2383

2384
  qDebug("%s total %" PRId64 " rows will merge, %p", __FUNCTION__, pInput->numOfRows, pInfo->pHisto);
88,772✔
2385

2386
  bool    hasRes = false;
88,772✔
2387
  int32_t start = pInput->startRowIndex;
88,772✔
2388
  for (int32_t i = start; i < start + pInput->numOfRows; ++i) {
180,128✔
2389
    char* data = colDataGetData(pCol, i);
91,356✔
2390

2391
    SAPercentileInfo* pInputInfo = (SAPercentileInfo*)varDataVal(data);
91,356✔
2392
    int32_t           code = apercentileTransferInfo(pInputInfo, pInfo, &hasRes);
91,356✔
2393
    if (TSDB_CODE_SUCCESS != code) {
91,356✔
2394
      return code;
×
2395
    }
2396
  }
2397

2398
  if (pInfo->algo != APERCT_ALGO_TDIGEST) {
88,772✔
2399
    buildHistogramInfo(pInfo);
72,249✔
2400
    qDebug("%s after merge, total:%" PRId64 ", numOfEntry:%d, %p", __FUNCTION__, pInfo->pHisto->numOfElems,
72,249✔
2401
           pInfo->pHisto->numOfEntries, pInfo->pHisto);
2402
  }
2403

2404
  SET_VAL(pResInfo, hasRes ? 1 : 0, 1);
88,772✔
2405
  return TSDB_CODE_SUCCESS;
88,772✔
2406
}
2407

2408
int32_t apercentileFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
26,265,803✔
2409
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
26,265,803✔
2410
  SAPercentileInfo*    pInfo = (SAPercentileInfo*)GET_ROWCELL_INTERBUF(pResInfo);
26,265,803✔
2411

2412
  if (pInfo->algo == APERCT_ALGO_TDIGEST) {
26,265,803✔
2413
    buildTDigestInfo(pInfo);
494,557✔
2414
    tdigestAutoFill(pInfo->pTDigest, COMPRESSION);
494,557✔
2415
    if (pInfo->pTDigest->size > 0) {
494,557✔
2416
      pInfo->result = tdigestQuantile(pInfo->pTDigest, pInfo->percent / 100);
494,557✔
2417
    } else {  // no need to free
2418
      // setNull(pCtx->pOutput, pCtx->outputType, pCtx->outputBytes);
2419
      return TSDB_CODE_SUCCESS;
×
2420
    }
2421
  } else {
2422
    buildHistogramInfo(pInfo);
25,771,246✔
2423
    if (pInfo->pHisto->numOfElems > 0) {
25,771,246✔
2424
      qDebug("%s get the final res, elements:%" PRId64 ", numOfEntry:%d, pHisto:%p, elems:%p", __FUNCTION__,
16,346,682✔
2425
             pInfo->pHisto->numOfElems, pInfo->pHisto->numOfEntries, pInfo->pHisto, pInfo->pHisto->elems);
2426

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

2445
  return functionFinalize(pCtx, pBlock);
26,265,803✔
2446
}
2447

2448
int32_t apercentilePartialFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
91,356✔
2449
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
91,356✔
2450
  SAPercentileInfo*    pInfo = (SAPercentileInfo*)GET_ROWCELL_INTERBUF(pResInfo);
91,356✔
2451

2452
  int32_t resultBytes = getApercentileMaxSize();
91,356✔
2453
  char*   res = taosMemoryCalloc(resultBytes + VARSTR_HEADER_SIZE, sizeof(char));
91,356✔
2454
  if (NULL == res) {
91,356✔
2455
    return terrno;
×
2456
  }
2457

2458
  if (pInfo->algo == APERCT_ALGO_TDIGEST) {
91,356✔
2459
    (void)memcpy(varDataVal(res), pInfo, resultBytes);
16,523✔
2460
    varDataSetLen(res, resultBytes);
16,523✔
2461
  } else {
2462
    (void)memcpy(varDataVal(res), pInfo, resultBytes);
74,833✔
2463
    varDataSetLen(res, resultBytes);
74,833✔
2464
  }
2465

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

2473
  int32_t code = colDataSetVal(pCol, pBlock->info.rows, res, false);
91,356✔
2474

2475
  taosMemoryFree(res);
91,356✔
2476
  return code;
91,356✔
2477
}
2478

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

2483
  SResultRowEntryInfo* pSResInfo = GET_RES_INFO(pSourceCtx);
×
2484
  SAPercentileInfo*    pSBuf = GET_ROWCELL_INTERBUF(pSResInfo);
×
2485

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

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

2497
// TODO: change this function when block data info pks changed
2498
static int32_t comparePkDataWithSValue(int8_t pkType, char* pkData, SValue* pVal, int32_t order) {
26,361✔
2499
  char numVal[8] = {0};
26,361✔
2500
  switch (pkType) {
26,361✔
2501
    case TSDB_DATA_TYPE_INT:
6,279✔
2502
      *(int32_t*)numVal = (int32_t)VALUE_GET_TRIVIAL_DATUM(pVal);
6,279✔
2503
      break;
6,279✔
2504
    case TSDB_DATA_TYPE_UINT:
2,724✔
2505
      *(uint32_t*)numVal = (uint32_t)VALUE_GET_TRIVIAL_DATUM(pVal);
2,724✔
2506
      break;
2,724✔
2507
    case TSDB_DATA_TYPE_BIGINT:
2,724✔
2508
      *(int64_t*)numVal = (int64_t)VALUE_GET_TRIVIAL_DATUM(pVal);
2,724✔
2509
      break;
2,724✔
2510
    case TSDB_DATA_TYPE_UBIGINT:
2,724✔
2511
      *(uint64_t*)numVal = (uint64_t)VALUE_GET_TRIVIAL_DATUM(pVal);
2,724✔
2512
      break;
2,724✔
2513
    default:
11,910✔
2514
      break;
11,910✔
2515
  }
2516
  char*         blockData = (IS_NUMERIC_TYPE(pkType)) ? (char*)numVal : (char*)pVal->pData;
26,361✔
2517
  __compar_fn_t fn = getKeyComparFunc(pkType, order);
26,361✔
2518
  return fn(pkData, blockData);
26,361✔
2519
}
2520

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

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

2529
  SFirstLastRes* pResult = GET_ROWCELL_INTERBUF(pEntry);
2,147,483,647✔
2530
  if (pResult->hasResult) {
2,147,483,647✔
2531
    if (pResult->pkBytes > 0) {
2,147,483,647✔
2532
      pResult->pkData = pResult->buf + pResult->bytes;
103,536✔
2533
    } else {
2534
      pResult->pkData = NULL;
2,147,483,647✔
2535
    }
2536
    if (pResult->ts < pBlockInfo->window.skey) {
2,147,483,647✔
2537
      return FUNC_DATA_REQUIRED_NOT_LOAD;
315,645✔
2538
    } else if (pResult->ts == pBlockInfo->window.skey) {
2,147,483,647✔
2539
      if (NULL == pResult->pkData) {
2,147,483,647✔
2540
        return FUNC_DATA_REQUIRED_NOT_LOAD;
2,147,483,647✔
2541
      }
2542
      if (comparePkDataWithSValue(pResult->pkType, pResult->pkData, pBlockInfo->pks + 0, TSDB_ORDER_ASC) < 0) {
5,472✔
2543
        return FUNC_DATA_REQUIRED_NOT_LOAD;
1,386✔
2544
      }
2545
    }
2546
    return FUNC_DATA_REQUIRED_DATA_LOAD;
150,873✔
2547
  } else {
2548
    return FUNC_DATA_REQUIRED_DATA_LOAD;
4,243✔
2549
  }
2550
}
2551

2552
EFuncDataRequired lastDynDataReq(void* pRes, SDataBlockInfo* pBlockInfo) {
21,829,869✔
2553
  SResultRowEntryInfo* pEntry = (SResultRowEntryInfo*)pRes;
21,829,869✔
2554

2555
  // not initialized yet, data is required
2556
  if (pEntry == NULL) {
21,829,869✔
2557
    return FUNC_DATA_REQUIRED_DATA_LOAD;
×
2558
  }
2559

2560
  SFirstLastRes* pResult = GET_ROWCELL_INTERBUF(pEntry);
21,829,869✔
2561
  if (pResult->hasResult) {
21,877,412✔
2562
    if (pResult->pkBytes > 0) {
21,881,980✔
2563
      pResult->pkData = pResult->buf + pResult->bytes;
266,049✔
2564
    } else {
2565
      pResult->pkData = NULL;
21,615,419✔
2566
    }
2567
    if (pResult->ts > pBlockInfo->window.ekey) {
21,880,956✔
2568
      return FUNC_DATA_REQUIRED_NOT_LOAD;
1,040,128✔
2569
    } else if (pResult->ts == pBlockInfo->window.ekey && pResult->pkData) {
20,840,316✔
2570
      if (comparePkDataWithSValue(pResult->pkType, pResult->pkData, pBlockInfo->pks + 1, TSDB_ORDER_DESC) < 0) {
20,889✔
2571
        return FUNC_DATA_REQUIRED_NOT_LOAD;
10,548✔
2572
      }
2573
    }
2574
    return FUNC_DATA_REQUIRED_DATA_LOAD;
20,821,696✔
2575
  } else {
2576
    return FUNC_DATA_REQUIRED_DATA_LOAD;
4,513✔
2577
  }
2578
}
2579

2580
// TODO modify it to include primary key bytes
2581
int32_t getFirstLastInfoSize(int32_t resBytes, int32_t pkBytes) { return sizeof(SFirstLastRes) + resBytes + pkBytes; }
985,629,972✔
2582

2583
bool getFirstLastFuncEnv(SFunctionNode* pFunc, SFuncExecEnv* pEnv) {
41,773,652✔
2584
  SColumnNode* pNode = (SColumnNode*)nodesListGetNode(pFunc->pParameterList, 0);
41,773,652✔
2585
  // TODO: change SFunctionNode to add pk info
2586
  int32_t pkBytes = (pFunc->hasPk) ? pFunc->pkBytes : 0;
41,781,671✔
2587
  pEnv->calcMemSize = getFirstLastInfoSize(pNode->node.resType.bytes, pkBytes);
41,772,317✔
2588
  return true;
41,769,259✔
2589
}
2590

2591
bool getSelectivityFuncEnv(SFunctionNode* pFunc, SFuncExecEnv* pEnv) {
9,172,741✔
2592
  SColumnNode* pNode = (SColumnNode*)nodesListGetNode(pFunc->pParameterList, 0);
9,172,741✔
2593
  pEnv->calcMemSize = pNode->node.resType.bytes;
9,173,763✔
2594
  return true;
9,173,933✔
2595
}
2596

2597
bool getGroupKeyFuncEnv(SFunctionNode* pFunc, SFuncExecEnv* pEnv) {
10,044,094✔
2598
  SColumnNode* pNode = (SColumnNode*)nodesListGetNode(pFunc->pParameterList, 0);
10,044,094✔
2599
  pEnv->calcMemSize = sizeof(SGroupKeyInfo) + pNode->node.resType.bytes;
10,048,357✔
2600
  return true;
10,045,658✔
2601
}
2602

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

2608
  return *(TSKEY*)colDataGetData(pTsColInfo, rowIndex);
2,147,483,647✔
2609
}
2610

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

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

2625
static int32_t prepareBuf(SqlFunctionCtx* pCtx) {
36,785,724✔
2626
  if (pCtx->subsidiaries.rowLen == 0) {
36,785,724✔
2627
    int32_t rowLen = 0;
3,621,063✔
2628
    for (int32_t j = 0; j < pCtx->subsidiaries.num; ++j) {
8,227,576✔
2629
      SqlFunctionCtx* pc = pCtx->subsidiaries.pCtx[j];
4,606,830✔
2630
      rowLen += pc->pExpr->base.resSchema.bytes;
4,606,542✔
2631
    }
2632

2633
    pCtx->subsidiaries.rowLen = rowLen + pCtx->subsidiaries.num * sizeof(bool);
3,619,700✔
2634
    pCtx->subsidiaries.buf = taosMemoryMalloc(pCtx->subsidiaries.rowLen);
3,620,051✔
2635
    if (NULL == pCtx->subsidiaries.buf) {
3,620,392✔
2636
      return terrno;
×
2637
    }
2638
  }
2639
  return TSDB_CODE_SUCCESS;
36,786,386✔
2640
}
2641

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

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

2650
  if (!pInfo->hasResult) {
5,187,027✔
2651
    code = saveTupleData(pCtx, rowIndex, pSrcBlock, &pInfo->pos);
3,906,962✔
2652
  } else if (!noElements) {
1,280,065✔
2653
    code = updateTupleData(pCtx, rowIndex, pSrcBlock, &pInfo->pos);
1,264,906✔
2654
  } else {
2655
  }  // dothing
2656

2657
  return code;
5,189,227✔
2658
}
2659

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

2665
  if (IS_VAR_DATA_TYPE(type)) {
2,147,483,647✔
2666
    pInfo->bytes = calcStrBytesByType(type, pData);
1,659,214,166✔
2667
    // if (type == TSDB_DATA_TYPE_JSON) {
2668
    //   pInfo->bytes = getJsonValueLen(pData);
2669
    // } else {
2670
    //   pInfo->bytes = varDataTLen(pData);
2671
    // }
2672
  }
2673

2674
  (void)memcpy(pInfo->buf, pData, pInfo->bytes);
2,147,483,647✔
2675
  if (pkData != NULL) {
2,147,483,647✔
2676
    if (IS_VAR_DATA_TYPE(pInfo->pkType)) {
2,697,250✔
2677
      pInfo->pkBytes = calcStrBytesByType(pInfo->pkType, pkData);
895,712✔
2678
      // if (pInfo->pkType == TSDB_DATA_TYPE_JSON) {
2679
      //   pInfo->pkBytes = getJsonValueLen(pkData);
2680
      // } else {
2681
      //   pInfo->pkBytes = varDataTLen(pkData);
2682
      // }
2683
    }
2684
    (void)memcpy(pInfo->buf + pInfo->bytes, pkData, pInfo->pkBytes);
2,697,250✔
2685
    pInfo->pkData = pInfo->buf + pInfo->bytes;
2,699,293✔
2686
  }
2687

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

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

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

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

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

2709
  pInfo->bytes = pInputCol->info.bytes;
2,147,483,647✔
2710

2711
  if (IS_NULL_TYPE(pInputCol->info.type)) {
2,147,483,647✔
2712
    return TSDB_CODE_SUCCESS;
708,269✔
2713
  }
2714

2715
  SColumnInfoData* pkCol = pInput->pPrimaryKey;
2,147,483,647✔
2716
  pInfo->pkType = -1;
2,147,483,647✔
2717
  __compar_fn_t pkCompareFn = NULL;
2,147,483,647✔
2718
  if (pCtx->hasPrimaryKey) {
2,147,483,647✔
2719
    pInfo->pkType = pkCol->info.type;
1,277,354✔
2720
    pInfo->pkBytes = pkCol->info.bytes;
1,277,354✔
2721
    pkCompareFn = getKeyComparFunc(pInfo->pkType, TSDB_ORDER_ASC);
1,276,673✔
2722
  }
2723

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

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

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

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

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

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

2759
      numOfElems++;
2760

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

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

2782
      numOfElems++;
2783

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

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

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

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

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

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

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

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

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

2845
  if (IS_NULL_TYPE(type)) {
2,147,483,647✔
2846
    return TSDB_CODE_SUCCESS;
646,710✔
2847
  }
2848
  pInfo->bytes = bytes;
2,147,483,647✔
2849

2850
  SColumnInfoData* pkCol = pInput->pPrimaryKey;
2,147,483,647✔
2851
  pInfo->pkType = -1;
2,147,483,647✔
2852
  __compar_fn_t pkCompareFn = NULL;
2,147,483,647✔
2853
  if (pCtx->hasPrimaryKey) {
2,147,483,647✔
2854
    pInfo->pkType = pkCol->info.type;
1,538,295✔
2855
    pInfo->pkBytes = pkCol->info.bytes;
1,540,338✔
2856
    pkCompareFn = getKeyComparFunc(pInfo->pkType, TSDB_ORDER_DESC);
1,538,976✔
2857
  }
2858

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

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

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

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

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

2886
      numOfElems++;
2887

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

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

2902
      numOfElems++;
2903

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

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

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

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

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

2937
    for (int32_t i = pInput->startRowIndex, tick = 0; tick < round; i += 4, tick += 1) {
2,147,483,647✔
2938
      int64_t cts = pts[i];
196,862,771✔
2939
      int32_t chosen = i;
196,858,997✔
2940

2941
      if (cts < pts[i + 1]) {
196,858,997✔
2942
        cts = pts[i + 1];
20,675,289✔
2943
        chosen = i + 1;
20,672,594✔
2944
      }
2945

2946
      if (cts < pts[i + 2]) {
196,861,902✔
2947
        cts = pts[i + 2];
20,676,138✔
2948
        chosen = i + 2;
20,692,847✔
2949
      }
2950

2951
      if (cts < pts[i + 3]) {
196,883,710✔
2952
        cts = pts[i + 3];
20,680,754✔
2953
        chosen = i + 3;
20,688,300✔
2954
      }
2955

2956
      if (pResInfo->numOfRes == 0 || pInfo->ts < cts) {
196,897,140✔
2957
        char*   data = colDataGetData(pInputCol, chosen);
33,989,127✔
2958
        int32_t code = doSaveCurrentVal(pCtx, chosen, cts, NULL, type, data);
33,985,438✔
2959
        if (code != TSDB_CODE_SUCCESS) {
33,992,129✔
2960
          return code;
×
2961
        }
2962
        pResInfo->numOfRes = 1;
33,992,129✔
2963
      }
2964
    }
2965

2966
    for (int32_t i = pInput->startRowIndex + round * 4; i < pInput->startRowIndex + pInput->numOfRows; ++i) {
2,147,483,647✔
2967
      if (pResInfo->numOfRes == 0 || pInfo->ts < pts[i]) {
2,147,483,647✔
2968
        char*   data = colDataGetData(pInputCol, i);
245,923,666✔
2969
        int32_t code = doSaveCurrentVal(pCtx, i, pts[i], NULL, type, data);
247,367,463✔
2970
        if (code != TSDB_CODE_SUCCESS) {
247,365,341✔
2971
          return code;
×
2972
        }
2973
        pResInfo->numOfRes = 1;
247,365,341✔
2974
      }
2975
    }
2976
  } else {
2977
    int     from = -1;
2,147,483,647✔
2978
    int32_t i = -1;
2,147,483,647✔
2979
    while (funcInputGetNextRowIndex(pInput, from, false, &i, &from)) {
2,147,483,647✔
2980
      if (colDataIsNull(pInputCol, pInput->totalRows, i, pColAgg)) {
2,147,483,647✔
2981
        continue;
2,147,483,647✔
2982
      }
2983

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

3005
#endif
3006

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

3016
  return TSDB_CODE_SUCCESS;
2,147,483,647✔
3017
}
3018

3019
static bool firstLastTransferInfoImpl(SFirstLastRes* pInput, SFirstLastRes* pOutput, bool isFirst) {
765,830,720✔
3020
  if (!pInput->hasResult) {
765,830,720✔
3021
    return false;
×
3022
  }
3023
  __compar_fn_t pkCompareFn = NULL;
765,830,720✔
3024
  if (pInput->pkData) {
765,830,720✔
3025
    pkCompareFn = getKeyComparFunc(pInput->pkType, (isFirst) ? TSDB_ORDER_ASC : TSDB_ORDER_DESC);
1,054,209✔
3026
  }
3027
  if (pOutput->hasResult) {
765,830,720✔
3028
    if (isFirst) {
410,452,594✔
3029
      if (pInput->ts > pOutput->ts ||
358,191,930✔
3030
          (pInput->ts == pOutput->ts && pkCompareFn && pkCompareFn(pInput->pkData, pOutput->pkData) > 0)) {
358,051,017✔
3031
        return false;
140,913✔
3032
      }
3033
    } else {
3034
      if (pInput->ts < pOutput->ts ||
52,260,664✔
3035
          (pInput->ts == pOutput->ts && pkCompareFn && pkCompareFn(pInput->pkData, pOutput->pkData) > 0)) {
51,181,445✔
3036
        return false;
1,079,219✔
3037
      }
3038
    }
3039
  }
3040

3041
  pOutput->isNull = pInput->isNull;
764,610,588✔
3042
  pOutput->ts = pInput->ts;
764,610,588✔
3043
  pOutput->bytes = pInput->bytes;
764,610,588✔
3044
  pOutput->pkType = pInput->pkType;
764,610,588✔
3045

3046
  (void)memcpy(pOutput->buf, pInput->buf, pOutput->bytes);
764,610,588✔
3047
  if (pInput->pkData) {
764,610,588✔
3048
    pOutput->pkBytes = pInput->pkBytes;
939,801✔
3049
    (void)memcpy(pOutput->buf + pOutput->bytes, pInput->pkData, pOutput->pkBytes);
939,801✔
3050
    pOutput->pkData = pOutput->buf + pOutput->bytes;
939,801✔
3051
  }
3052
  return true;
764,610,588✔
3053
}
3054

3055
static int32_t firstLastTransferInfo(SqlFunctionCtx* pCtx, SFirstLastRes* pInput, SFirstLastRes* pOutput, bool isFirst,
765,830,720✔
3056
                                     int32_t rowIndex) {
3057
  if (firstLastTransferInfoImpl(pInput, pOutput, isFirst)) {
765,830,720✔
3058
    int32_t code = firstlastSaveTupleData(pCtx->pSrcBlock, rowIndex, pCtx, pOutput, false);
764,610,588✔
3059
    if (TSDB_CODE_SUCCESS != code) {
764,610,588✔
3060
      return code;
×
3061
    }
3062
    pOutput->hasResult = true;
764,610,588✔
3063
  }
3064
  return TSDB_CODE_SUCCESS;
765,830,720✔
3065
}
3066

3067
static int32_t firstLastFunctionMergeImpl(SqlFunctionCtx* pCtx, bool isFirstQuery) {
360,526,315✔
3068
  SInputColumnInfoData* pInput = &pCtx->input;
360,526,315✔
3069
  SColumnInfoData*      pCol = pInput->pData[0];
360,526,315✔
3070

3071
  if (IS_NULL_TYPE(pCol->info.type)) {
360,526,315✔
3072
    SET_VAL(GET_RES_INFO(pCtx), 0, 1);
×
3073
    return TSDB_CODE_SUCCESS;
×
3074
  }
3075

3076
  if (pCol->info.type != TSDB_DATA_TYPE_BINARY) {
360,526,315✔
3077
    return TSDB_CODE_FUNC_FUNTION_PARA_TYPE;
×
3078
  }
3079

3080
  SFirstLastRes* pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
360,526,315✔
3081

3082
  int32_t start = pInput->startRowIndex;
360,526,315✔
3083
  int32_t numOfElems = 0;
360,526,315✔
3084

3085
  for (int32_t i = start; i < start + pInput->numOfRows; ++i) {
1,243,556,557✔
3086
    if (colDataIsNull_s(pCol, i)) {
1,766,060,484✔
3087
      continue;
117,199,522✔
3088
    }
3089
    char*          data = colDataGetData(pCol, i);
765,830,720✔
3090
    SFirstLastRes* pInputInfo = (SFirstLastRes*)varDataVal(data);
765,830,720✔
3091
    if (pCtx->hasPrimaryKey) {
765,830,720✔
3092
      pInputInfo->pkData = pInputInfo->buf + pInputInfo->bytes;
1,054,209✔
3093
    } else {
3094
      pInputInfo->pkData = NULL;
764,776,511✔
3095
    }
3096

3097
    int32_t code = firstLastTransferInfo(pCtx, pInputInfo, pInfo, isFirstQuery, i);
765,830,720✔
3098
    if (code != TSDB_CODE_SUCCESS) {
765,830,720✔
3099
      return code;
×
3100
    }
3101
    if (!numOfElems) {
765,830,720✔
3102
      numOfElems = pInputInfo->hasResult ? 1 : 0;
359,669,625✔
3103
    }
3104
  }
3105

3106
  if (numOfElems == 0) {
360,526,315✔
3107
    int32_t code = firstlastSaveTupleData(pCtx->pSrcBlock, pInput->startRowIndex, pCtx, pInfo, true);
856,690✔
3108
    if (code != TSDB_CODE_SUCCESS) {
856,690✔
3109
      return code;
×
3110
    }
3111
    pInfo->nullTupleSaved = true;
856,690✔
3112
  }
3113

3114
  SET_VAL(GET_RES_INFO(pCtx), numOfElems, 1);
360,526,315✔
3115
  return TSDB_CODE_SUCCESS;
360,526,315✔
3116
}
3117

3118
int32_t firstFunctionMerge(SqlFunctionCtx* pCtx) { return firstLastFunctionMergeImpl(pCtx, true); }
211,759,819✔
3119

3120
int32_t lastFunctionMerge(SqlFunctionCtx* pCtx) { return firstLastFunctionMergeImpl(pCtx, false); }
148,766,496✔
3121

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

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

3133
  SFirstLastRes* pRes = GET_ROWCELL_INTERBUF(pResInfo);
2,147,483,647✔
3134

3135
  if (pResInfo->isNullRes) {
2,147,483,647✔
3136
    colDataSetNULL(pCol, pBlock->info.rows);
539,336,803✔
3137
    return setNullSelectivityValue(pCtx, pBlock, pBlock->info.rows);
539,336,803✔
3138
  }
3139
  code = colDataSetVal(pCol, pBlock->info.rows, pRes->buf, pRes->isNull || pResInfo->isNullRes);
2,147,483,647✔
3140
  if (TSDB_CODE_SUCCESS != code) {
2,147,483,647✔
3141
    return code;
×
3142
  }
3143

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

3150
  return code;
2,147,483,647✔
3151
}
3152

3153
int32_t firstLastPartialFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
937,845,582✔
3154
  int32_t code = TSDB_CODE_SUCCESS;
937,845,582✔
3155

3156
  SResultRowEntryInfo* pEntryInfo = GET_RES_INFO(pCtx);
937,845,582✔
3157
  SFirstLastRes*       pRes = GET_ROWCELL_INTERBUF(pEntryInfo);
937,990,694✔
3158

3159
  int32_t resultBytes = getFirstLastInfoSize(pRes->bytes, pRes->pkBytes);
937,989,810✔
3160

3161
  // todo check for failure
3162
  char* res = taosMemoryCalloc(resultBytes + VARSTR_HEADER_SIZE, sizeof(char));
937,952,295✔
3163
  if (NULL == res) {
936,789,811✔
3164
    return terrno;
×
3165
  }
3166
  (void)memcpy(varDataVal(res), pRes, resultBytes);
936,789,811✔
3167

3168
  varDataSetLen(res, resultBytes);
936,785,407✔
3169

3170
  int32_t          slotId = pCtx->pExpr->base.resSchema.slotId;
937,820,592✔
3171
  SColumnInfoData* pCol = taosArrayGet(pBlock->pDataBlock, slotId);
937,858,243✔
3172
  if (NULL == pCol) {
937,674,681✔
3173
    taosMemoryFree(res);
×
3174
    return TSDB_CODE_OUT_OF_RANGE;
×
3175
  }
3176

3177
  if (pEntryInfo->numOfRes == 0) {
937,674,681✔
3178
    colDataSetNULL(pCol, pBlock->info.rows);
122,596,750✔
3179
    code = setNullSelectivityValue(pCtx, pBlock, pBlock->info.rows);
122,603,209✔
3180
  } else {
3181
    code = colDataSetVal(pCol, pBlock->info.rows, res, false);
815,124,453✔
3182
    if (TSDB_CODE_SUCCESS != code) {
815,270,554✔
3183
      taosMemoryFree(res);
×
3184
      return code;
×
3185
    }
3186
    code = setSelectivityValue(pCtx, pBlock, &pRes->pos, pBlock->info.rows);
815,270,554✔
3187
  }
3188
  taosMemoryFree(res);
937,669,401✔
3189
  return code;
937,654,672✔
3190
}
3191

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

3197
  SResultRowEntryInfo* pSResInfo = GET_RES_INFO(pSourceCtx);
×
3198
  SFirstLastRes*       pSBuf = GET_ROWCELL_INTERBUF(pSResInfo);
×
3199

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

3206
static int32_t doSaveLastrow(SqlFunctionCtx* pCtx, char* pData, int32_t rowIndex, int64_t cts, SFirstLastRes* pInfo) {
18,248,545✔
3207
  SInputColumnInfoData* pInput = &pCtx->input;
18,248,545✔
3208
  SColumnInfoData*      pInputCol = pInput->pData[0];
18,249,757✔
3209
  SColumnInfoData*      pkCol = pInput->pPrimaryKey;
18,259,078✔
3210

3211
  if (colDataIsNull_s(pInputCol, rowIndex)) {
36,531,506✔
3212
    pInfo->isNull = true;
590,902✔
3213
  } else {
3214
    pInfo->isNull = false;
17,672,625✔
3215

3216
    if (IS_VAR_DATA_TYPE(pInputCol->info.type)) {
17,667,417✔
3217
      pInfo->bytes = calcStrBytesByType(pInputCol->info.type, pData);
2,882,545✔
3218
      // if (pInputCol->info.type == TSDB_DATA_TYPE_JSON) {
3219
      //   pInfo->bytes = getJsonValueLen(pData);
3220
      // } else {
3221
      //   pInfo->bytes = varDataTLen(pData);
3222
      // }
3223
    }
3224

3225
    (void)memcpy(pInfo->buf, pData, pInfo->bytes);
17,671,251✔
3226
  }
3227

3228
  if (pCtx->hasPrimaryKey && !colDataIsNull_s(pkCol, rowIndex)) {
19,510,925✔
3229
    char* pkData = colDataGetData(pkCol, rowIndex);
1,248,558✔
3230
    if (IS_VAR_DATA_TYPE(pInfo->pkType)) {
1,252,644✔
3231
      pInfo->pkBytes = calcStrBytesByType(pInfo->pkType, pkData);
416,427✔
3232
    }
3233
    (void)memcpy(pInfo->buf + pInfo->bytes, pkData, pInfo->pkBytes);
1,250,601✔
3234
    pInfo->pkData = pInfo->buf + pInfo->bytes;
1,249,239✔
3235
  }
3236
  pInfo->ts = cts;
18,266,426✔
3237
  int32_t code = firstlastSaveTupleData(pCtx->pSrcBlock, rowIndex, pCtx, pInfo, false);
18,256,944✔
3238
  if (code != TSDB_CODE_SUCCESS) {
18,256,750✔
3239
    return code;
×
3240
  }
3241

3242
  pInfo->hasResult = true;
18,256,750✔
3243

3244
  return TSDB_CODE_SUCCESS;
18,260,262✔
3245
}
3246

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

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

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

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

3260
  if (IS_NULL_TYPE(type)) {
2,147,483,647✔
3261
    return TSDB_CODE_SUCCESS;
34,648✔
3262
  }
3263
  SColumnInfoData* pkCol = pInput->pPrimaryKey;
2,147,483,647✔
3264
  pInfo->pkType = -1;
2,147,483,647✔
3265
  __compar_fn_t pkCompareFn = NULL;
2,147,483,647✔
3266
  if (pCtx->hasPrimaryKey) {
2,147,483,647✔
3267
    pInfo->pkType = pkCol->info.type;
1,240,329✔
3268
    pInfo->pkBytes = pkCol->info.bytes;
1,241,010✔
3269
    pkCompareFn = getKeyComparFunc(pInfo->pkType, TSDB_ORDER_DESC);
1,240,329✔
3270
  }
3271
  TSKEY startKey = getRowPTs(pInput->pPTS, 0);
2,147,483,647✔
3272
  TSKEY endKey = getRowPTs(pInput->pPTS, pInput->totalRows - 1);
2,147,483,647✔
3273

3274
  if (pCtx->order == TSDB_ORDER_ASC && !pCtx->hasPrimaryKey) {
2,147,483,647✔
3275
    for (int32_t i = pInput->numOfRows + pInput->startRowIndex - 1; i >= pInput->startRowIndex; --i) {
23,493,741✔
3276
      bool  isNull = colDataIsNull(pInputCol, pInput->numOfRows, i, NULL);
11,745,607✔
3277
      char* data = isNull ? NULL : colDataGetData(pInputCol, i);
11,738,131✔
3278
      TSKEY cts = getRowPTs(pInput->pPTS, i);
11,744,158✔
3279
      numOfElems++;
11,749,646✔
3280

3281
      if (pResInfo->numOfRes == 0 || pInfo->ts < cts) {
11,749,646✔
3282
        int32_t code = doSaveLastrow(pCtx, data, i, cts, pInfo);
2,982,055✔
3283
        if (code != TSDB_CODE_SUCCESS) return code;
2,983,462✔
3284
      }
3285

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

3297
      if (pResInfo->numOfRes == 0 || pInfo->ts < cts) {
2,147,483,647✔
3298
        int32_t code = doSaveLastrow(pCtx, data, i, cts, pInfo);
19,415,527✔
3299
        if (code != TSDB_CODE_SUCCESS) return code;
11,571,161✔
3300
      }
3301
      break;
2,147,483,647✔
3302
    }
3303
  } else {
3304
    int64_t* pts = (int64_t*)pInput->pPTS->pData;
2,204,144✔
3305
    int      from = -1;
1,926,709✔
3306
    int32_t  i = -1;
1,926,709✔
3307
    while (funcInputGetNextRowIndex(pInput, from, false, &i, &from)) {
9,577,849✔
3308
      bool  isNull = colDataIsNull(pInputCol, pInput->numOfRows, i, NULL);
7,650,956✔
3309
      char* data = isNull ? NULL : colDataGetData(pInputCol, i);
7,652,318✔
3310
      TSKEY cts = pts[i];
7,651,547✔
3311

3312
      numOfElems++;
7,650,001✔
3313
      char* pkData = NULL;
7,650,001✔
3314
      if (pCtx->hasPrimaryKey) {
7,650,001✔
3315
        pkData = colDataGetData(pkCol, i);
3,167,334✔
3316
      }
3317
      if (pResInfo->numOfRes == 0 || pInfo->ts < cts ||
7,653,864✔
3318
          (pInfo->ts == pts[i] && pkCompareFn && pkCompareFn(pkData, pInfo->pkData) < 0)) {
4,390,359✔
3319
        int32_t code = doSaveLastrow(pCtx, data, i, cts, pInfo);
3,263,121✔
3320
        if (code != TSDB_CODE_SUCCESS) {
3,266,069✔
3321
          return code;
×
3322
        }
3323
        pResInfo->numOfRes = 1;
3,266,069✔
3324
      }
3325
    }
3326
  }
3327

3328
  SET_VAL(pResInfo, numOfElems, 1);
2,147,483,647✔
3329
  return TSDB_CODE_SUCCESS;
2,147,483,647✔
3330
}
3331

3332
bool getDiffFuncEnv(SFunctionNode* UNUSED_PARAM(pFunc), SFuncExecEnv* pEnv) {
295,442✔
3333
  pEnv->calcMemSize = sizeof(SDiffInfo);
295,442✔
3334
  return true;
295,442✔
3335
}
3336

3337
int32_t diffFunctionSetup(SqlFunctionCtx* pCtx, SResultRowEntryInfo* pResInfo) {
17,512,999✔
3338
  if (pResInfo->initialized) {
17,512,999✔
3339
    return TSDB_CODE_SUCCESS;
15,775,722✔
3340
  }
3341
  if (TSDB_CODE_SUCCESS != functionSetup(pCtx, pResInfo)) {
1,737,277✔
3342
    return TSDB_CODE_FUNC_SETUP_ERROR;
×
3343
  }
3344
  SDiffInfo* pDiffInfo = GET_ROWCELL_INTERBUF(pResInfo);
1,737,277✔
3345
  pDiffInfo->hasPrev = false;
1,737,277✔
3346
  pDiffInfo->isFirstRow = true;
1,737,277✔
3347
  pDiffInfo->prev.i64 = 0;
1,737,277✔
3348
  pDiffInfo->prevTs = -1;
1,737,277✔
3349
  if (pCtx->numOfParams > 1) {
1,737,277✔
3350
    pDiffInfo->ignoreOption = pCtx->param[1].param.i;  // TODO set correct param
1,737,277✔
3351
  } else {
3352
    pDiffInfo->ignoreOption = 0;
×
3353
  }
3354
  return TSDB_CODE_SUCCESS;
1,737,277✔
3355
}
3356

3357
static int32_t doSetPrevVal(SDiffInfo* pDiffInfo, int32_t type, const char* pv, int64_t ts) {
1,686,302✔
3358
  switch (type) {
1,686,302✔
3359
    case TSDB_DATA_TYPE_BOOL:
4,598✔
3360
      pDiffInfo->prev.i64 = *(bool*)pv ? 1 : 0;
4,598✔
3361
      break;
4,598✔
3362
    case TSDB_DATA_TYPE_UTINYINT:
26,831✔
3363
    case TSDB_DATA_TYPE_TINYINT:
3364
      pDiffInfo->prev.i64 = *(int8_t*)pv;
26,831✔
3365
      break;
26,831✔
3366
    case TSDB_DATA_TYPE_UINT:
1,443,575✔
3367
    case TSDB_DATA_TYPE_INT:
3368
      pDiffInfo->prev.i64 = *(int32_t*)pv;
1,443,575✔
3369
      break;
1,443,575✔
3370
    case TSDB_DATA_TYPE_USMALLINT:
28,881✔
3371
    case TSDB_DATA_TYPE_SMALLINT:
3372
      pDiffInfo->prev.i64 = *(int16_t*)pv;
28,881✔
3373
      break;
28,881✔
3374
    case TSDB_DATA_TYPE_TIMESTAMP:
106,302✔
3375
    case TSDB_DATA_TYPE_UBIGINT:
3376
    case TSDB_DATA_TYPE_BIGINT:
3377
      pDiffInfo->prev.i64 = *(int64_t*)pv;
106,302✔
3378
      break;
106,302✔
3379
    case TSDB_DATA_TYPE_FLOAT:
18,938✔
3380
      pDiffInfo->prev.d64 = *(float*)pv;
18,938✔
3381
      break;
18,938✔
3382
    case TSDB_DATA_TYPE_DOUBLE:
57,177✔
3383
      pDiffInfo->prev.d64 = *(double*)pv;
57,177✔
3384
      break;
57,177✔
3385
    default:
×
3386
      return TSDB_CODE_FUNC_FUNTION_PARA_TYPE;
×
3387
  }
3388
  pDiffInfo->prevTs = ts;
1,686,302✔
3389
  pDiffInfo->hasPrev = true;
1,686,302✔
3390
  return TSDB_CODE_SUCCESS;
1,686,302✔
3391
}
3392

3393
static bool diffIsNegtive(SDiffInfo* pDiffInfo, int32_t type, const char* pv) {
649,492✔
3394
  switch (type) {
649,492✔
3395
    case TSDB_DATA_TYPE_UINT: {
×
3396
      int64_t v = *(uint32_t*)pv;
×
3397
      return v < pDiffInfo->prev.i64;
×
3398
    }
3399
    case TSDB_DATA_TYPE_INT: {
90,078✔
3400
      int64_t v = *(int32_t*)pv;
90,078✔
3401
      return v < pDiffInfo->prev.i64;
90,078✔
3402
    }
3403
    case TSDB_DATA_TYPE_BOOL: {
×
3404
      int64_t v = *(bool*)pv;
×
3405
      return v < pDiffInfo->prev.i64;
×
3406
    }
3407
    case TSDB_DATA_TYPE_UTINYINT: {
×
3408
      int64_t v = *(uint8_t*)pv;
×
3409
      return v < pDiffInfo->prev.i64;
×
3410
    }
3411
    case TSDB_DATA_TYPE_TINYINT: {
206,840✔
3412
      int64_t v = *(int8_t*)pv;
206,840✔
3413
      return v < pDiffInfo->prev.i64;
206,840✔
3414
    }
3415
    case TSDB_DATA_TYPE_USMALLINT: {
×
3416
      int64_t v = *(uint16_t*)pv;
×
3417
      return v < pDiffInfo->prev.i64;
×
3418
    }
3419
    case TSDB_DATA_TYPE_SMALLINT: {
73,306✔
3420
      int64_t v = *(int16_t*)pv;
73,306✔
3421
      return v < pDiffInfo->prev.i64;
73,306✔
3422
    }
3423
    case TSDB_DATA_TYPE_UBIGINT: {
4,088✔
3424
      uint64_t v = *(uint64_t*)pv;
4,088✔
3425
      return v < (uint64_t)pDiffInfo->prev.i64;
4,088✔
3426
    }
3427
    case TSDB_DATA_TYPE_TIMESTAMP:
44,678✔
3428
    case TSDB_DATA_TYPE_BIGINT: {
3429
      int64_t v = *(int64_t*)pv;
44,678✔
3430
      return v < pDiffInfo->prev.i64;
44,678✔
3431
    }
3432
    case TSDB_DATA_TYPE_FLOAT: {
174,160✔
3433
      float v = *(float*)pv;
174,160✔
3434
      return v < pDiffInfo->prev.d64;
174,160✔
3435
    }
3436
    case TSDB_DATA_TYPE_DOUBLE: {
56,342✔
3437
      double v = *(double*)pv;
56,342✔
3438
      return v < pDiffInfo->prev.d64;
56,342✔
3439
    }
3440
    default:
×
3441
      return false;
×
3442
  }
3443

3444
  return false;
3445
}
3446

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

3462
static void tryToSetDouble(SDiffInfo* pDiffInfo, SColumnInfoData* pOutput, double v, int32_t pos) {
32,297,279✔
3463
  double delta = v - pDiffInfo->prev.d64;
32,297,279✔
3464
  if (delta < 0 && ignoreNegative(pDiffInfo->ignoreOption)) {
32,297,279✔
3465
    colDataSetNull_f_s(pOutput, pos);
114,411✔
3466
  } else {
3467
    colDataSetDouble(pOutput, pos, &delta);
32,182,868✔
3468
  }
3469
  pDiffInfo->prev.d64 = v;
32,297,279✔
3470
}
32,297,279✔
3471

3472
static int32_t doHandleDiff(SDiffInfo* pDiffInfo, int32_t type, const char* pv, SColumnInfoData* pOutput, int32_t pos,
2,147,483,647✔
3473
                            int64_t ts) {
3474
  if (!pDiffInfo->hasPrev) {
2,147,483,647✔
3475
    colDataSetNull_f_s(pOutput, pos);
75,192✔
3476
    return doSetPrevVal(pDiffInfo, type, pv, ts);
75,192✔
3477
  }
3478
  pDiffInfo->prevTs = ts;
2,147,483,647✔
3479
  switch (type) {
2,147,483,647✔
3480
    case TSDB_DATA_TYPE_UINT: {
70,007✔
3481
      int64_t v = *(uint32_t*)pv;
70,007✔
3482
      tryToSetInt64(pDiffInfo, type, pOutput, v, pos);
70,007✔
3483
      break;
70,007✔
3484
    }
3485
    case TSDB_DATA_TYPE_INT: {
677,998,440✔
3486
      int64_t v = *(int32_t*)pv;
677,998,440✔
3487
      tryToSetInt64(pDiffInfo, type, pOutput, v, pos);
677,998,440✔
3488
      break;
677,998,440✔
3489
    }
3490
    case TSDB_DATA_TYPE_BOOL: {
5,205,027✔
3491
      int64_t v = *(bool*)pv;
5,205,027✔
3492
      tryToSetInt64(pDiffInfo, type, pOutput, v, pos);
5,205,027✔
3493
      break;
5,205,027✔
3494
    }
3495
    case TSDB_DATA_TYPE_UTINYINT: {
68,985✔
3496
      int64_t v = *(uint8_t*)pv;
68,985✔
3497
      tryToSetInt64(pDiffInfo, type, pOutput, v, pos);
68,985✔
3498
      break;
68,985✔
3499
    }
3500
    case TSDB_DATA_TYPE_TINYINT: {
10,437,267✔
3501
      int64_t v = *(int8_t*)pv;
10,437,267✔
3502
      tryToSetInt64(pDiffInfo, type, pOutput, v, pos);
10,437,267✔
3503
      break;
10,437,267✔
3504
    }
3505
    case TSDB_DATA_TYPE_USMALLINT: {
68,985✔
3506
      int64_t v = *(uint16_t*)pv;
68,985✔
3507
      tryToSetInt64(pDiffInfo, type, pOutput, v, pos);
68,985✔
3508
      break;
68,985✔
3509
    }
3510
    case TSDB_DATA_TYPE_SMALLINT: {
10,821,547✔
3511
      int64_t v = *(int16_t*)pv;
10,821,547✔
3512
      tryToSetInt64(pDiffInfo, type, pOutput, v, pos);
10,821,547✔
3513
      break;
10,821,547✔
3514
    }
3515
    case TSDB_DATA_TYPE_TIMESTAMP:
2,147,483,647✔
3516
    case TSDB_DATA_TYPE_UBIGINT:
3517
    case TSDB_DATA_TYPE_BIGINT: {
3518
      int64_t v = *(int64_t*)pv;
2,147,483,647✔
3519
      tryToSetInt64(pDiffInfo, type, pOutput, v, pos);
2,147,483,647✔
3520
      break;
2,147,483,647✔
3521
    }
3522
    case TSDB_DATA_TYPE_FLOAT: {
16,116,382✔
3523
      double v = *(float*)pv;
16,116,382✔
3524
      tryToSetDouble(pDiffInfo, pOutput, v, pos);
16,116,382✔
3525
      break;
16,116,382✔
3526
    }
3527
    case TSDB_DATA_TYPE_DOUBLE: {
16,180,897✔
3528
      double v = *(double*)pv;
16,180,897✔
3529
      tryToSetDouble(pDiffInfo, pOutput, v, pos);
16,180,897✔
3530
      break;
16,180,897✔
3531
    }
3532
    default:
×
3533
      return TSDB_CODE_FUNC_FUNTION_PARA_TYPE;
×
3534
  }
3535
  pDiffInfo->hasPrev = true;
2,147,483,647✔
3536
  return TSDB_CODE_SUCCESS;
2,147,483,647✔
3537
}
3538

3539
// TODO: the primary key compare can be skipped for ordered pk if knonwn before
3540
// TODO: for desc ordered, pk shall select the smallest one for one ts. if across block boundaries.
3541
bool funcInputGetNextRowIndex(SInputColumnInfoData* pInput, int32_t from, bool firstOccur, int32_t* pRowIndex,
2,147,483,647✔
3542
                              int32_t* nextFrom) {
3543
  if (pInput->pPrimaryKey == NULL) {
2,147,483,647✔
3544
    if (from == -1) {
2,147,483,647✔
3545
      from = pInput->startRowIndex;
2,147,483,647✔
3546
    } else if (from >= pInput->numOfRows + pInput->startRowIndex) {
2,147,483,647✔
3547
      return false;
2,147,483,647✔
3548
    }
3549
    *pRowIndex = from;
2,147,483,647✔
3550
    *nextFrom = from + 1;
2,147,483,647✔
3551
    return true;
2,147,483,647✔
3552
  } else {
3553
    if (from == -1) {
14,330,126✔
3554
      from = pInput->startRowIndex;
4,060,064✔
3555
    } else if (from >= pInput->numOfRows + pInput->startRowIndex) {
10,270,062✔
3556
      return false;
4,064,150✔
3557
    }
3558
    TSKEY*           tsList = (int64_t*)pInput->pPTS->pData;
10,265,976✔
3559
    SColumnInfoData* pkCol = pInput->pPrimaryKey;
10,265,295✔
3560
    int8_t           pkType = pkCol->info.type;
10,263,252✔
3561
    int32_t          order = (firstOccur) ? TSDB_ORDER_ASC : TSDB_ORDER_DESC;
10,262,571✔
3562
    __compar_fn_t    compareFunc = getKeyComparFunc(pkType, order);
10,262,571✔
3563
    int32_t          select = from;
10,263,933✔
3564
    char*            val = colDataGetData(pkCol, select);
10,263,933✔
3565
    while (from < pInput->numOfRows + pInput->startRowIndex - 1 && tsList[from + 1] == tsList[from]) {
19,903,844✔
3566
      char* val1 = colDataGetData(pkCol, from + 1);
9,629,696✔
3567
      if (compareFunc(val1, val) < 0) {
9,629,015✔
3568
        select = from + 1;
1,592✔
3569
        val = val1;
1,592✔
3570
      }
3571
      from = from + 1;
9,629,015✔
3572
    }
3573
    *pRowIndex = select;
10,257,804✔
3574
    *nextFrom = from + 1;
10,269,381✔
3575
    return true;
10,266,657✔
3576
  }
3577
}
3578

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

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

3588
  if (pRow->isDataNull || !pDiffInfo->hasPrev) {
2,147,483,647✔
3589
    return true;
4,637,932✔
3590
  } else if (ignoreNegative(pDiffInfo->ignoreOption)) {
2,147,483,647✔
3591
    return diffIsNegtive(pDiffInfo, pCtx->input.pData[0]->info.type, pRow->pData);
649,492✔
3592
  }
3593
  return false;
2,147,483,647✔
3594
}
3595

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

3602
int32_t trySetPreVal(SqlFunctionCtx* pCtx, SFuncInputRow* pRow) {
1,748,854✔
3603
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
1,748,854✔
3604
  SDiffInfo*           pDiffInfo = GET_ROWCELL_INTERBUF(pResInfo);
1,748,854✔
3605
  pDiffInfo->isFirstRow = false;
1,748,854✔
3606
  if (pRow->isDataNull) {
1,748,854✔
3607
    return TSDB_CODE_SUCCESS;
137,744✔
3608
  }
3609

3610
  SInputColumnInfoData* pInput = &pCtx->input;
1,611,110✔
3611
  SColumnInfoData*      pInputCol = pInput->pData[0];
1,611,110✔
3612
  int8_t                inputType = pInputCol->info.type;
1,611,110✔
3613

3614
  char* pv = pRow->pData;
1,611,110✔
3615
  return doSetPrevVal(pDiffInfo, inputType, pv, pRow->ts);
1,611,110✔
3616
}
3617

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

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

3631
    // handle selectivity
3632
    if (pCtx->subsidiaries.num > 0) {
2,822,573✔
3633
      code = appendSelectivityCols(pCtx, pRow->block, pRow->rowIndex, pos);
24,526✔
3634
      if (code != TSDB_CODE_SUCCESS) {
24,526✔
3635
        return code;
×
3636
      }
3637
    }
3638
    return TSDB_CODE_SUCCESS;
2,822,573✔
3639
  }
3640

3641
  char* pv = pRow->pData;
2,147,483,647✔
3642

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

3658
  return TSDB_CODE_SUCCESS;
2,147,483,647✔
3659
}
3660

3661
int32_t diffFunction(SqlFunctionCtx* pCtx) { return TSDB_CODE_SUCCESS; }
17,217,557✔
3662

3663
int32_t diffFunctionByRow(SArray* pCtxArray) {
17,189,963✔
3664
  int32_t code = TSDB_CODE_SUCCESS;
17,189,963✔
3665
  int     diffColNum = pCtxArray->size;
17,189,963✔
3666
  if (diffColNum == 0) {
17,189,963✔
3667
    return TSDB_CODE_SUCCESS;
×
3668
  }
3669
  int32_t numOfElems = 0;
17,189,963✔
3670

3671
  SArray* pRows = taosArrayInit_s(sizeof(SFuncInputRow), diffColNum);
17,189,963✔
3672
  if (NULL == pRows) {
17,189,963✔
3673
    return terrno;
×
3674
  }
3675

3676
  bool keepNull = false;
17,189,963✔
3677
  for (int i = 0; i < diffColNum; ++i) {
34,407,520✔
3678
    SqlFunctionCtx* pCtx = *(SqlFunctionCtx**)taosArrayGet(pCtxArray, i);
17,217,557✔
3679
    if (NULL == pCtx) {
17,217,557✔
3680
      code = terrno;
×
3681
      goto _exit;
×
3682
    }
3683
    funcInputUpdate(pCtx);
17,217,557✔
3684
    SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
17,217,557✔
3685
    SDiffInfo*           pDiffInfo = GET_ROWCELL_INTERBUF(pResInfo);
17,217,557✔
3686
    if (!ignoreNull(pDiffInfo->ignoreOption)) {
17,217,557✔
3687
      keepNull = true;
17,196,606✔
3688
    }
3689
  }
3690

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

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

3754
  for (int i = 0; i < diffColNum; ++i) {
34,388,791✔
3755
    SqlFunctionCtx* pCtx = *(SqlFunctionCtx**)taosArrayGet(pCtxArray, i);
17,207,937✔
3756
    if (NULL == pCtx) {
17,207,937✔
3757
      code = terrno;
×
3758
      goto _exit;
×
3759
    }
3760
    SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
17,207,937✔
3761
    pResInfo->numOfRes = numOfElems;
17,207,937✔
3762
  }
3763

3764
_exit:
17,189,963✔
3765
  if (pRows) {
17,189,963✔
3766
    taosArrayDestroy(pRows);
17,189,963✔
3767
    pRows = NULL;
17,189,963✔
3768
  }
3769
  return code;
17,189,963✔
3770
}
3771

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

3774
bool getTopBotFuncEnv(SFunctionNode* pFunc, SFuncExecEnv* pEnv) {
1,769,025✔
3775
  SValueNode* pkNode = (SValueNode*)nodesListGetNode(pFunc->pParameterList, 1);
1,769,025✔
3776
  pEnv->calcMemSize = sizeof(STopBotRes) + pkNode->datum.i * sizeof(STopBotResItem);
1,769,025✔
3777
  return true;
1,769,025✔
3778
}
3779

3780
int32_t topBotFunctionSetup(SqlFunctionCtx* pCtx, SResultRowEntryInfo* pResInfo) {
7,341,765✔
3781
  if (pResInfo->initialized) {
7,341,765✔
3782
    return TSDB_CODE_SUCCESS;
×
3783
  }
3784
  if (TSDB_CODE_SUCCESS != functionSetup(pCtx, pResInfo)) {
7,343,268✔
3785
    return TSDB_CODE_FUNC_SETUP_ERROR;
×
3786
  }
3787

3788
  STopBotRes*           pRes = GET_ROWCELL_INTERBUF(pResInfo);
7,340,681✔
3789
  SInputColumnInfoData* pInput = &pCtx->input;
7,340,681✔
3790

3791
  pRes->maxSize = pCtx->param[1].param.i;
7,341,264✔
3792

3793
  pRes->nullTupleSaved = false;
7,343,186✔
3794
  pRes->nullTuplePos.pageId = -1;
7,343,268✔
3795
  return TSDB_CODE_SUCCESS;
7,340,180✔
3796
}
3797

3798
static STopBotRes* getTopBotOutputInfo(SqlFunctionCtx* pCtx) {
1,225,546,615✔
3799
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
1,225,546,615✔
3800
  STopBotRes*          pRes = GET_ROWCELL_INTERBUF(pResInfo);
1,225,562,188✔
3801
  pRes->pItems = (STopBotResItem*)((char*)pRes + sizeof(STopBotRes));
1,225,591,262✔
3802

3803
  return pRes;
1,225,565,993✔
3804
}
3805

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

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

3811
int32_t topFunction(SqlFunctionCtx* pCtx) {
7,509,242✔
3812
  int32_t              numOfElems = 0;
7,509,242✔
3813
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
7,509,242✔
3814

3815
  SInputColumnInfoData* pInput = &pCtx->input;
7,510,244✔
3816
  SColumnInfoData*      pCol = pInput->pData[0];
7,510,745✔
3817

3818
  STopBotRes* pRes = getTopBotOutputInfo(pCtx);
7,510,326✔
3819
  pRes->type = pInput->pData[0]->info.type;
7,510,991✔
3820

3821
  int32_t start = pInput->startRowIndex;
7,511,993✔
3822
  for (int32_t i = start; i < pInput->numOfRows + start; ++i) {
828,715,497✔
3823
    if (pCol->hasNull && colDataIsNull_f(pCol, i)) {
821,228,784✔
3824
      continue;
969,316✔
3825
    }
3826

3827
    numOfElems++;
820,210,255✔
3828
    char*   data = colDataGetData(pCol, i);
820,210,255✔
3829
    int32_t code = doAddIntoResult(pCtx, data, i, pCtx->pSrcBlock, pRes->type, pInput->uid, pResInfo, true);
820,550,044✔
3830
    if (code != TSDB_CODE_SUCCESS) {
820,234,270✔
3831
      return code;
×
3832
    }
3833
  }
3834

3835
  if (numOfElems == 0 && pCtx->subsidiaries.num > 0 && !pRes->nullTupleSaved) {
7,515,828✔
3836
    int32_t code = saveTupleData(pCtx, pInput->startRowIndex, pCtx->pSrcBlock, &pRes->nullTuplePos);
3,776✔
3837
    if (code != TSDB_CODE_SUCCESS) {
3,776✔
3838
      return code;
×
3839
    }
3840
    pRes->nullTupleSaved = true;
3,776✔
3841
  }
3842
  return TSDB_CODE_SUCCESS;
7,515,828✔
3843
}
3844

3845
int32_t bottomFunction(SqlFunctionCtx* pCtx) {
696,737✔
3846
  int32_t              numOfElems = 0;
696,737✔
3847
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
696,737✔
3848

3849
  SInputColumnInfoData* pInput = &pCtx->input;
696,737✔
3850
  SColumnInfoData*      pCol = pInput->pData[0];
696,737✔
3851

3852
  STopBotRes* pRes = getTopBotOutputInfo(pCtx);
696,737✔
3853
  pRes->type = pInput->pData[0]->info.type;
696,737✔
3854

3855
  int32_t start = pInput->startRowIndex;
696,737✔
3856
  for (int32_t i = start; i < pInput->numOfRows + start; ++i) {
391,360,462✔
3857
    if (pCol->hasNull && colDataIsNull_f(pCol, i)) {
390,662,617✔
3858
      continue;
593,752✔
3859
    }
3860

3861
    numOfElems++;
390,067,597✔
3862
    char*   data = colDataGetData(pCol, i);
390,067,597✔
3863
    int32_t code = doAddIntoResult(pCtx, data, i, pCtx->pSrcBlock, pRes->type, pInput->uid, pResInfo, false);
390,097,228✔
3864
    if (code != TSDB_CODE_SUCCESS) {
390,069,973✔
3865
      return code;
×
3866
    }
3867
  }
3868

3869
  if (numOfElems == 0 && pCtx->subsidiaries.num > 0 && !pRes->nullTupleSaved) {
696,737✔
3870
    int32_t code = saveTupleData(pCtx, pInput->startRowIndex, pCtx->pSrcBlock, &pRes->nullTuplePos);
3,814✔
3871
    if (code != TSDB_CODE_SUCCESS) {
3,814✔
3872
      return code;
×
3873
    }
3874
    pRes->nullTupleSaved = true;
3,814✔
3875
  }
3876

3877
  return TSDB_CODE_SUCCESS;
696,737✔
3878
}
3879

3880
static int32_t topBotResComparFn(const void* p1, const void* p2, const void* param) {
405,245,643✔
3881
  uint16_t type = *(uint16_t*)param;
405,245,643✔
3882

3883
  STopBotResItem* val1 = (STopBotResItem*)p1;
405,295,390✔
3884
  STopBotResItem* val2 = (STopBotResItem*)p2;
405,295,390✔
3885

3886
  if (IS_SIGNED_NUMERIC_TYPE(type)) {
405,295,390✔
3887
    if (val1->v.i == val2->v.i) {
220,474,592✔
3888
      return 0;
46,033,196✔
3889
    }
3890

3891
    return (val1->v.i > val2->v.i) ? 1 : -1;
174,970,379✔
3892
  } else if (IS_UNSIGNED_NUMERIC_TYPE(type)) {
184,820,798✔
3893
    if (val1->v.u == val2->v.u) {
88,592,248✔
3894
      return 0;
18,678,330✔
3895
    }
3896

3897
    return (val1->v.u > val2->v.u) ? 1 : -1;
70,061,381✔
3898
  } else if (TSDB_DATA_TYPE_FLOAT == type) {
96,228,550✔
3899
    if (val1->v.f == val2->v.f) {
1,602,325✔
3900
      return 0;
32,319✔
3901
    }
3902

3903
    return (val1->v.f > val2->v.f) ? 1 : -1;
1,570,006✔
3904
  }
3905

3906
  if (val1->v.d == val2->v.d) {
94,626,225✔
3907
    return 0;
5,643✔
3908
  }
3909

3910
  return (val1->v.d > val2->v.d) ? 1 : -1;
94,766,939✔
3911
}
3912

3913
int32_t doAddIntoResult(SqlFunctionCtx* pCtx, void* pData, int32_t rowIndex, SSDataBlock* pSrcBlock, uint16_t type,
1,210,194,109✔
3914
                        uint64_t uid, SResultRowEntryInfo* pEntryInfo, bool isTopQuery) {
3915
  STopBotRes* pRes = getTopBotOutputInfo(pCtx);
1,210,194,109✔
3916
  int32_t     code = TSDB_CODE_SUCCESS;
1,209,982,251✔
3917

3918
  SVariant val = {0};
1,209,982,251✔
3919
  TAOS_CHECK_RETURN(taosVariantCreateFromBinary(&val, pData, tDataTypes[type].bytes, type));
1,209,976,986✔
3920

3921
  STopBotResItem* pItems = pRes->pItems;
1,210,318,175✔
3922

3923
  // not full yet
3924
  if (pEntryInfo->numOfRes < pRes->maxSize) {
1,210,401,504✔
3925
    STopBotResItem* pItem = &pItems[pEntryInfo->numOfRes];
40,024,821✔
3926
    pItem->v = val;
40,024,739✔
3927
    pItem->uid = uid;
40,024,739✔
3928

3929
    // save the data of this tuple
3930
    if (pCtx->subsidiaries.num > 0) {
40,027,153✔
3931
      code = saveTupleData(pCtx, rowIndex, pSrcBlock, &pItem->tuplePos);
8,039,798✔
3932
      if (code != TSDB_CODE_SUCCESS) {
8,039,824✔
3933
        return code;
×
3934
      }
3935
    }
3936
#ifdef BUF_PAGE_DEBUG
3937
    qDebug("page_saveTuple i:%d, item:%p,pageId:%d, offset:%d\n", pEntryInfo->numOfRes, pItem, pItem->tuplePos.pageId,
3938
           pItem->tuplePos.offset);
3939
#endif
3940
    // allocate the buffer and keep the data of this row into the new allocated buffer
3941
    pEntryInfo->numOfRes++;
40,021,582✔
3942
    code = taosheapsort((void*)pItems, sizeof(STopBotResItem), pEntryInfo->numOfRes, (const void*)&type,
40,024,415✔
3943
                        topBotResComparFn, !isTopQuery);
40,023,750✔
3944
    if (code != TSDB_CODE_SUCCESS) {
40,025,836✔
3945
      return code;
×
3946
    }
3947
  } else {  // replace the minimum value in the result
3948
    if ((isTopQuery && ((IS_SIGNED_NUMERIC_TYPE(type) && val.i > pItems[0].v.i) ||
1,170,374,180✔
3949
                        (IS_UNSIGNED_NUMERIC_TYPE(type) && val.u > pItems[0].v.u) ||
770,871,048✔
3950
                        (TSDB_DATA_TYPE_FLOAT == type && val.f > pItems[0].v.f) ||
761,643,150✔
3951
                        (TSDB_DATA_TYPE_DOUBLE == type && val.d > pItems[0].v.d))) ||
761,584,676✔
3952
        (!isTopQuery && ((IS_SIGNED_NUMERIC_TYPE(type) && val.i < pItems[0].v.i) ||
1,138,167,892✔
3953
                         (IS_UNSIGNED_NUMERIC_TYPE(type) && val.u < pItems[0].v.u) ||
386,250,507✔
3954
                         (TSDB_DATA_TYPE_FLOAT == type && val.f < pItems[0].v.f) ||
386,007,573✔
3955
                         (TSDB_DATA_TYPE_DOUBLE == type && val.d < pItems[0].v.d)))) {
385,931,476✔
3956
      // replace the old data and the coresponding tuple data
3957
      STopBotResItem* pItem = &pItems[0];
33,408,270✔
3958
      pItem->v = val;
33,408,270✔
3959
      pItem->uid = uid;
33,315,765✔
3960

3961
      // save the data of this tuple by over writing the old data
3962
      if (pCtx->subsidiaries.num > 0) {
33,333,428✔
3963
        code = updateTupleData(pCtx, rowIndex, pSrcBlock, &pItem->tuplePos);
20,583,557✔
3964
        if (code != TSDB_CODE_SUCCESS) {
20,580,050✔
3965
          return code;
×
3966
        }
3967
      }
3968
#ifdef BUF_PAGE_DEBUG
3969
      qDebug("page_copyTuple pageId:%d, offset:%d", pItem->tuplePos.pageId, pItem->tuplePos.offset);
3970
#endif
3971
      code = taosheapadjust((void*)pItems, sizeof(STopBotResItem), 0, pEntryInfo->numOfRes - 1, (const void*)&type,
33,330,586✔
3972
                            topBotResComparFn, NULL, !isTopQuery);
33,330,003✔
3973
      if (code != TSDB_CODE_SUCCESS) {
33,320,265✔
3974
        return code;
×
3975
      }
3976
    }
3977
  }
3978

3979
  return TSDB_CODE_SUCCESS;
1,210,322,169✔
3980
}
3981

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

3993
  int32_t offset = 0;
36,790,384✔
3994
  for (int32_t i = 0; i < pSubsidiaryies->num; ++i) {
83,339,360✔
3995
    SqlFunctionCtx* pc = pSubsidiaryies->pCtx[i];
46,546,901✔
3996

3997
    // group_key function has its own process function
3998
    // do not process there
3999
    if (fmIsGroupKeyFunc(pc->functionId)) {
46,550,981✔
4000
      continue;
×
4001
    }
4002

4003
    SFunctParam* pFuncParam = &pc->pExpr->base.pParam[0];
46,538,946✔
4004
    int32_t      srcSlotId = pFuncParam->pCol->slotId;
46,543,353✔
4005

4006
    SColumnInfoData* pCol = taosArrayGet(pSrcBlock->pDataBlock, srcSlotId);
46,539,197✔
4007
    if (NULL == pCol) {
46,536,931✔
4008
      return TSDB_CODE_OUT_OF_RANGE;
×
4009
    }
4010
    if ((nullList[i] = colDataIsNull_s(pCol, rowIndex)) == true) {
93,075,095✔
4011
      offset += pCol->info.bytes;
208,087✔
4012
      continue;
208,087✔
4013
    }
4014

4015
    char* p = colDataGetData(pCol, rowIndex);
46,327,987✔
4016
    if (IS_VAR_DATA_TYPE(pCol->info.type)) {
46,336,448✔
4017
      int32_t bytes = calcStrBytesByType(pCol->info.type, p);
9,061,559✔
4018
      (void)memcpy(pStart + offset, p, bytes);
9,070,972✔
4019
    } else {
4020
      (void)memcpy(pStart + offset, p, pCol->info.bytes);
37,267,688✔
4021
    }
4022

4023
    offset += pCol->info.bytes;
46,343,907✔
4024
  }
4025

4026
  *res = buf;
36,769,510✔
4027
  return TSDB_CODE_SUCCESS;
36,790,989✔
4028
}
4029

4030
static int32_t doSaveTupleData(SSerializeDataHandle* pHandle, const void* pBuf, size_t length, SWinKey* key,
46,728,045✔
4031
                               STuplePos* pPos, SFunctionStateStore* pStore) {
4032
  STuplePos p = {0};
46,728,045✔
4033
  if (pHandle->pBuf != NULL) {
46,728,045✔
4034
    SFilePage* pPage = NULL;
46,736,914✔
4035

4036
    if (pHandle->currentPage == -1) {
46,736,914✔
4037
      pPage = getNewBufPage(pHandle->pBuf, &pHandle->currentPage);
3,819,391✔
4038
      if (pPage == NULL) {
3,823,335✔
4039
        return terrno;
×
4040
      }
4041
      pPage->num = sizeof(SFilePage);
3,823,335✔
4042
    } else {
4043
      pPage = getBufPage(pHandle->pBuf, pHandle->currentPage);
42,913,999✔
4044
      if (pPage == NULL) {
42,910,332✔
4045
        return terrno;
×
4046
      }
4047
      if (pPage->num + length > getBufPageSize(pHandle->pBuf)) {
42,910,332✔
4048
        // current page is all used, let's prepare a new buffer page
4049
        releaseBufPage(pHandle->pBuf, pPage);
828,492✔
4050
        pPage = getNewBufPage(pHandle->pBuf, &pHandle->currentPage);
828,492✔
4051
        if (pPage == NULL) {
828,492✔
4052
          return terrno;
×
4053
        }
4054
        pPage->num = sizeof(SFilePage);
828,492✔
4055
      }
4056
    }
4057

4058
    p = (STuplePos){.pageId = pHandle->currentPage, .offset = pPage->num};
46,734,473✔
4059
    (void)memcpy(pPage->data + pPage->num, pBuf, length);
46,734,678✔
4060

4061
    pPage->num += length;
46,731,970✔
4062
    setBufPageDirty(pPage, true);
46,724,331✔
4063
    releaseBufPage(pHandle->pBuf, pPage);
46,723,302✔
4064
  } else {  // other tuple save policy
UNCOV
4065
    if (pStore->streamStateFuncPut(pHandle->pState, key, pBuf, length) >= 0) {
×
4066
      p.streamTupleKey = *key;
×
4067
    }
4068
  }
4069

4070
  *pPos = p;
46,725,697✔
4071
  return TSDB_CODE_SUCCESS;
46,723,673✔
4072
}
4073

4074
int32_t saveTupleData(SqlFunctionCtx* pCtx, int32_t rowIndex, const SSDataBlock* pSrcBlock, STuplePos* pPos) {
13,877,432✔
4075
  int32_t code = prepareBuf(pCtx);
13,877,432✔
4076
  if (TSDB_CODE_SUCCESS != code) {
13,874,547✔
4077
    return code;
×
4078
  }
4079

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

4094
  char* buf = NULL;
13,875,903✔
4095
  code = serializeTupleData(pSrcBlock, rowIndex, &pCtx->subsidiaries, pCtx->subsidiaries.buf, &buf);
13,876,734✔
4096
  if (TSDB_CODE_SUCCESS != code) {
13,874,818✔
4097
    return code;
×
4098
  }
4099
  return doSaveTupleData(&pCtx->saveHandle, buf, pCtx->subsidiaries.rowLen, &key, pPos, pCtx->pStore);
13,874,818✔
4100
}
4101

4102
static int32_t doUpdateTupleData(SSerializeDataHandle* pHandle, const void* pBuf, size_t length, STuplePos* pPos,
22,912,176✔
4103
                                 SFunctionStateStore* pStore) {
4104
  if (pHandle->pBuf != NULL) {
22,912,176✔
4105
    SFilePage* pPage = getBufPage(pHandle->pBuf, pPos->pageId);
22,913,679✔
4106
    if (pPage == NULL) {
22,916,767✔
4107
      return terrno;
×
4108
    }
4109
    (void)memcpy(pPage->data + pPos->offset, pBuf, length);
22,916,767✔
4110
    setBufPageDirty(pPage, true);
22,915,264✔
4111
    releaseBufPage(pHandle->pBuf, pPage);
22,914,681✔
4112
  } else {
4113
    int32_t code = pStore->streamStateFuncPut(pHandle->pState, &pPos->streamTupleKey, pBuf, length);
×
4114
    if (TSDB_CODE_SUCCESS != code) {
×
4115
      return code;
×
4116
    }
4117
  }
4118

4119
  return TSDB_CODE_SUCCESS;
22,910,172✔
4120
}
4121

4122
int32_t updateTupleData(SqlFunctionCtx* pCtx, int32_t rowIndex, const SSDataBlock* pSrcBlock, STuplePos* pPos) {
22,913,342✔
4123
  int32_t code = prepareBuf(pCtx);
22,913,342✔
4124
  if (TSDB_CODE_SUCCESS != code) {
22,914,845✔
4125
    return code;
×
4126
  }
4127

4128
  char* buf = NULL;
22,914,845✔
4129
  code = serializeTupleData(pSrcBlock, rowIndex, &pCtx->subsidiaries, pCtx->subsidiaries.buf, &buf);
22,914,845✔
4130
  if (TSDB_CODE_SUCCESS != code) {
22,914,599✔
4131
    return code;
×
4132
  }
4133
  return doUpdateTupleData(&pCtx->saveHandle, buf, pCtx->subsidiaries.rowLen, pPos, pCtx->pStore);
22,914,599✔
4134
}
4135

4136
static int32_t doLoadTupleData(SSerializeDataHandle* pHandle, const STuplePos* pPos, SFunctionStateStore* pStore,
13,827,215✔
4137
                               char** value) {
4138
  if (pHandle->pBuf != NULL) {
13,827,215✔
4139
    SFilePage* pPage = getBufPage(pHandle->pBuf, pPos->pageId);
13,827,703✔
4140
    if (pPage == NULL) {
13,827,703✔
4141
      *value = NULL;
×
4142
      return terrno;
×
4143
    }
4144
    *value = pPage->data + pPos->offset;
13,827,703✔
4145
    releaseBufPage(pHandle->pBuf, pPage);
13,827,192✔
4146
    return TSDB_CODE_SUCCESS;
13,826,681✔
4147
  } else {
4148
    *value = NULL;
×
4149
    int32_t vLen;
×
4150
    int32_t code = pStore->streamStateFuncGet(pHandle->pState, &pPos->streamTupleKey, (void**)(value), &vLen);
×
4151
    if (TSDB_CODE_SUCCESS != code) {
×
4152
      return code;
×
4153
    }
4154
    return TSDB_CODE_SUCCESS;
×
4155
  }
4156
}
4157

4158
int32_t loadTupleData(SqlFunctionCtx* pCtx, const STuplePos* pPos, char** value) {
13,827,703✔
4159
  return doLoadTupleData(&pCtx->saveHandle, pPos, pCtx->pStore, value);
13,827,703✔
4160
}
4161

4162
int32_t topBotFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
7,344,352✔
4163
  int32_t code = TSDB_CODE_SUCCESS;
7,344,352✔
4164

4165
  SResultRowEntryInfo* pEntryInfo = GET_RES_INFO(pCtx);
7,344,352✔
4166
  STopBotRes*          pRes = getTopBotOutputInfo(pCtx);
7,344,352✔
4167

4168
  int16_t type = pCtx->pExpr->base.resSchema.type;
7,344,352✔
4169
  int32_t slotId = pCtx->pExpr->base.resSchema.slotId;
7,344,352✔
4170

4171
  SColumnInfoData* pCol = taosArrayGet(pBlock->pDataBlock, slotId);
7,344,352✔
4172
  if (NULL == pCol) {
7,343,851✔
4173
    return TSDB_CODE_OUT_OF_RANGE;
×
4174
  }
4175

4176
  // todo assign the tag value and the corresponding row data
4177
  int32_t currentRow = pBlock->info.rows;
7,343,851✔
4178
  if (pEntryInfo->numOfRes <= 0) {
7,344,352✔
4179
    colDataSetNULL(pCol, currentRow);
16,696✔
4180
    code = setSelectivityValue(pCtx, pBlock, &pRes->nullTuplePos, currentRow);
16,696✔
4181
    return code;
16,696✔
4182
  }
4183
  for (int32_t i = 0; i < pEntryInfo->numOfRes; ++i) {
47,371,319✔
4184
    STopBotResItem* pItem = &pRes->pItems[i];
40,043,663✔
4185
    code = colDataSetVal(pCol, currentRow, (const char*)&pItem->v.i, false);
40,043,663✔
4186
    if (TSDB_CODE_SUCCESS != code) {
40,043,663✔
4187
      return code;
×
4188
    }
4189
#ifdef BUF_PAGE_DEBUG
4190
    qDebug("page_finalize i:%d,item:%p,pageId:%d, offset:%d\n", i, pItem, pItem->tuplePos.pageId,
4191
           pItem->tuplePos.offset);
4192
#endif
4193
    code = setSelectivityValue(pCtx, pBlock, &pRes->pItems[i].tuplePos, currentRow);
40,043,663✔
4194
    if (TSDB_CODE_SUCCESS != code) {
40,043,663✔
4195
      return code;
×
4196
    }
4197
    currentRow += 1;
40,043,663✔
4198
  }
4199

4200
  return code;
7,327,656✔
4201
}
4202

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

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

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

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

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

4276
int32_t getSpreadInfoSize() { return (int32_t)sizeof(SSpreadInfo); }
7,958,534✔
4277

4278
bool getSpreadFuncEnv(SFunctionNode* UNUSED_PARAM(pFunc), SFuncExecEnv* pEnv) {
1,504,021✔
4279
  pEnv->calcMemSize = sizeof(SSpreadInfo);
1,504,021✔
4280
  return true;
1,504,182✔
4281
}
4282

4283
int32_t spreadFunctionSetup(SqlFunctionCtx* pCtx, SResultRowEntryInfo* pResultInfo) {
85,276,681✔
4284
  if (pResultInfo->initialized) {
85,276,681✔
4285
    return TSDB_CODE_SUCCESS;
×
4286
  }
4287
  if (TSDB_CODE_SUCCESS != functionSetup(pCtx, pResultInfo)) {
85,278,119✔
4288
    return TSDB_CODE_FUNC_SETUP_ERROR;
×
4289
  }
4290

4291
  SSpreadInfo* pInfo = GET_ROWCELL_INTERBUF(pResultInfo);
85,280,317✔
4292
  SET_DOUBLE_VAL(&pInfo->min, DBL_MAX);
85,280,441✔
4293
  SET_DOUBLE_VAL(&pInfo->max, -DBL_MAX);
85,279,908✔
4294
  pInfo->hasResult = false;
85,280,441✔
4295
  return TSDB_CODE_SUCCESS;
85,280,565✔
4296
}
4297

4298
int32_t spreadFunction(SqlFunctionCtx* pCtx) {
89,562,478✔
4299
  int32_t numOfElems = 0;
89,562,478✔
4300

4301
  // Only the pre-computing information loaded and actual data does not loaded
4302
  SInputColumnInfoData* pInput = &pCtx->input;
89,562,478✔
4303
  SColumnDataAgg*       pAgg = pInput->pColumnDataAgg[0];
89,563,209✔
4304
  int32_t               type = pInput->pData[0]->info.type;
89,569,597✔
4305

4306
  SSpreadInfo* pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
89,571,170✔
4307

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

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

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

4333
  } else {  // computing based on the true data block
4334
    SColumnInfoData* pCol = pInput->pData[0];
89,570,154✔
4335

4336
    int32_t start = pInput->startRowIndex;
89,567,688✔
4337
    // check the valid data one by one
4338
    for (int32_t i = start; i < pInput->numOfRows + start; ++i) {
470,406,832✔
4339
      if (colDataIsNull_f(pCol, i)) {
380,840,336✔
4340
        continue;
67,063,220✔
4341
      }
4342

4343
      char* data = colDataGetData(pCol, i);
313,772,994✔
4344

4345
      double v = 0;
313,784,447✔
4346
      GET_TYPED_DATA(v, double, type, data, typeGetTypeModFromColInfo(&pCol->info));
313,784,447✔
4347
      if (v < GET_DOUBLE_VAL(&pInfo->min)) {
313,783,841✔
4348
        SET_DOUBLE_VAL(&pInfo->min, v);
60,340,836✔
4349
      }
4350

4351
      if (v > GET_DOUBLE_VAL(&pInfo->max)) {
313,778,193✔
4352
        SET_DOUBLE_VAL(&pInfo->max, v);
75,074,057✔
4353
      }
4354

4355
      numOfElems += 1;
313,774,040✔
4356
    }
4357
  }
4358

4359
_spread_over:
89,569,166✔
4360
  // data in the check operation are all null, not output
4361
  SET_VAL(GET_RES_INFO(pCtx), numOfElems, 1);
89,569,166✔
4362
  if (numOfElems > 0) {
89,566,516✔
4363
    pInfo->hasResult = true;
64,976,903✔
4364
  }
4365

4366
  return TSDB_CODE_SUCCESS;
89,566,144✔
4367
}
4368

4369
static void spreadTransferInfo(SSpreadInfo* pInput, SSpreadInfo* pOutput) {
7,832,964✔
4370
  pOutput->hasResult = pInput->hasResult;
7,832,964✔
4371
  if (pInput->max > pOutput->max) {
7,832,964✔
4372
    pOutput->max = pInput->max;
5,469,822✔
4373
  }
4374

4375
  if (pInput->min < pOutput->min) {
7,832,964✔
4376
    pOutput->min = pInput->min;
5,467,690✔
4377
  }
4378
}
7,832,964✔
4379

4380
int32_t spreadFunctionMerge(SqlFunctionCtx* pCtx) {
5,506,584✔
4381
  SInputColumnInfoData* pInput = &pCtx->input;
5,506,584✔
4382
  SColumnInfoData*      pCol = pInput->pData[0];
5,506,584✔
4383

4384
  if (IS_NULL_TYPE(pCol->info.type)) {
5,506,584✔
4385
    SET_VAL(GET_RES_INFO(pCtx), 0, 1);
×
4386
    return TSDB_CODE_SUCCESS;
×
4387
  }
4388

4389
  if (pCol->info.type != TSDB_DATA_TYPE_BINARY) {
5,506,584✔
4390
    return TSDB_CODE_FUNC_FUNTION_PARA_TYPE;
×
4391
  }
4392

4393
  SSpreadInfo* pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
5,506,584✔
4394

4395
  int32_t start = pInput->startRowIndex;
5,506,584✔
4396
  for (int32_t i = start; i < start + pInput->numOfRows; ++i) {
13,354,011✔
4397
    if (colDataIsNull_s(pCol, i)) continue;
15,694,854✔
4398
    char*        data = colDataGetData(pCol, i);
7,847,427✔
4399
    SSpreadInfo* pInputInfo = (SSpreadInfo*)varDataVal(data);
7,847,427✔
4400
    if (pInputInfo->hasResult) {
7,847,427✔
4401
      spreadTransferInfo(pInputInfo, pInfo);
7,832,964✔
4402
    }
4403
  }
4404

4405
  if (pInfo->hasResult) {
5,506,584✔
4406
    GET_RES_INFO(pCtx)->numOfRes = 1;
5,492,121✔
4407
  }
4408

4409
  return TSDB_CODE_SUCCESS;
5,506,584✔
4410
}
4411

4412
int32_t spreadFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
71,496,945✔
4413
  SSpreadInfo* pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
71,496,945✔
4414
  if (pInfo->hasResult == true) {
71,496,945✔
4415
    SET_DOUBLE_VAL(&pInfo->result, pInfo->max - pInfo->min);
47,063,528✔
4416
  } else {
4417
    GET_RES_INFO(pCtx)->isNullRes = 1;
24,433,102✔
4418
  }
4419
  return functionFinalize(pCtx, pBlock);
71,496,791✔
4420
}
4421

4422
int32_t spreadPartialFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
7,861,365✔
4423
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
7,861,365✔
4424
  SSpreadInfo*         pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
7,861,365✔
4425
  int32_t              resultBytes = getSpreadInfoSize();
7,861,365✔
4426
  char*                res = taosMemoryCalloc(resultBytes + VARSTR_HEADER_SIZE, sizeof(char));
7,860,759✔
4427

4428
  if (NULL == res) {
7,860,153✔
4429
    return terrno;
×
4430
  }
4431
  (void)memcpy(varDataVal(res), pInfo, resultBytes);
7,860,153✔
4432
  varDataSetLen(res, resultBytes);
7,860,153✔
4433

4434
  int32_t          slotId = pCtx->pExpr->base.resSchema.slotId;
7,859,547✔
4435
  int32_t          code = TSDB_CODE_SUCCESS;
7,860,759✔
4436
  SColumnInfoData* pCol = taosArrayGet(pBlock->pDataBlock, slotId);
7,860,759✔
4437
  if (NULL == pCol) {
7,861,971✔
4438
    code = terrno;
×
4439
    goto _exit;
×
4440
  }
4441

4442
  code = colDataSetVal(pCol, pBlock->info.rows, res, false);
7,861,971✔
4443
  if (TSDB_CODE_SUCCESS != code) {
7,861,365✔
4444
    goto _exit;
×
4445
  }
4446

4447
_exit:
7,861,365✔
4448
  taosMemoryFree(res);
7,861,365✔
4449
  return code;
7,861,971✔
4450
}
4451

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

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

4464
int32_t getElapsedInfoSize() { return (int32_t)sizeof(SElapsedInfo); }
×
4465

4466
bool getElapsedFuncEnv(SFunctionNode* UNUSED_PARAM(pFunc), SFuncExecEnv* pEnv) {
1,243,325✔
4467
  pEnv->calcMemSize = sizeof(SElapsedInfo);
1,243,325✔
4468
  return true;
1,243,325✔
4469
}
4470

4471
int32_t elapsedFunctionSetup(SqlFunctionCtx* pCtx, SResultRowEntryInfo* pResultInfo) {
2,207,249✔
4472
  if (pResultInfo->initialized) {
2,207,249✔
4473
    return TSDB_CODE_SUCCESS;
×
4474
  }
4475
  if (TSDB_CODE_SUCCESS != functionSetup(pCtx, pResultInfo)) {
2,207,934✔
4476
    return TSDB_CODE_FUNC_SETUP_ERROR;
×
4477
  }
4478

4479
  SElapsedInfo* pInfo = GET_ROWCELL_INTERBUF(pResultInfo);
2,208,982✔
4480
  pInfo->result = 0;
2,207,612✔
4481
  pInfo->min = TSKEY_MAX;
2,209,345✔
4482
  pInfo->max = 0;
2,207,249✔
4483

4484
  if (pCtx->numOfParams > 1) {
2,207,410✔
4485
    pInfo->timeUnit = pCtx->param[1].param.i;
1,664,399✔
4486
  } else {
4487
    pInfo->timeUnit = 1;
542,528✔
4488
  }
4489

4490
  return TSDB_CODE_SUCCESS;
2,209,506✔
4491
}
4492

4493
int32_t elapsedFunction(SqlFunctionCtx* pCtx) {
2,206,725✔
4494
  int32_t numOfElems = 0;
2,206,725✔
4495

4496
  // Only the pre-computing information loaded and actual data does not loaded
4497
  SInputColumnInfoData* pInput = &pCtx->input;
2,206,725✔
4498
  SColumnDataAgg*       pAgg = pInput->pColumnDataAgg[0];
2,207,249✔
4499

4500
  SElapsedInfo* pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
2,208,982✔
4501

4502
  numOfElems = pInput->numOfRows;  // since this is the primary timestamp, no need to exclude NULL values
2,207,249✔
4503
  if (numOfElems == 0) {
2,205,516✔
4504
    // for stream
4505
    if (pCtx->end.key != INT64_MIN) {
×
4506
      pInfo->max = pCtx->end.key + 1;
×
4507
    }
4508
    goto _elapsed_over;
×
4509
  }
4510

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

4536
    SColumnInfoData* pCol = pInput->pData[0];
2,204,348✔
4537

4538
    int32_t start = pInput->startRowIndex;
2,208,297✔
4539
    TSKEY*  ptsList = (int64_t*)colDataGetData(pCol, 0);
2,207,249✔
4540
    if (pCtx->order == TSDB_ORDER_DESC) {
2,206,564✔
4541
      if (pCtx->start.key == INT64_MIN) {
32,236✔
4542
        pInfo->max = (pInfo->max < ptsList[start]) ? ptsList[start] : pInfo->max;
32,236✔
4543
      } else {
4544
        pInfo->max = pCtx->start.key + 1;
×
4545
      }
4546

4547
      if (pCtx->end.key == INT64_MIN) {
32,236✔
4548
        pInfo->min =
32,236✔
4549
            (pInfo->min > ptsList[start + pInput->numOfRows - 1]) ? ptsList[start + pInput->numOfRows - 1] : pInfo->min;
32,236✔
4550
      } else {
4551
        pInfo->min = pCtx->end.key;
×
4552
      }
4553
    } else {
4554
      if (pCtx->start.key == INT64_MIN) {
2,172,595✔
4555
        pInfo->min = (pInfo->min > ptsList[start]) ? ptsList[start] : pInfo->min;
2,171,506✔
4556
      } else {
4557
        pInfo->min = pCtx->start.key;
4,192✔
4558
      }
4559

4560
      if (pCtx->end.key == INT64_MIN) {
2,175,900✔
4561
        pInfo->max =
2,109,574✔
4562
            (pInfo->max < ptsList[start + pInput->numOfRows - 1]) ? ptsList[start + pInput->numOfRows - 1] : pInfo->max;
2,111,146✔
4563
      } else {
4564
        pInfo->max = pCtx->end.key + 1;
64,230✔
4565
      }
4566
    }
4567
  }
4568

4569
_elapsed_over:
2,204,468✔
4570
  // data in the check operation are all null, not output
4571
  SET_VAL(GET_RES_INFO(pCtx), numOfElems, 1);
2,204,468✔
4572

4573
  return TSDB_CODE_SUCCESS;
2,205,677✔
4574
}
4575

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

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

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

4594
  SElapsedInfo* pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
×
4595

4596
  int32_t start = pInput->startRowIndex;
×
4597

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

4604
  SET_VAL(GET_RES_INFO(pCtx), 1, 1);
×
4605
  return TSDB_CODE_SUCCESS;
×
4606
}
4607

4608
int32_t elapsedFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
2,209,506✔
4609
  SElapsedInfo* pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
2,209,506✔
4610
  double        result = (double)(pInfo->max - pInfo->min);
2,209,506✔
4611
  pInfo->result = fabs(result) / pInfo->timeUnit;
2,209,506✔
4612
  return functionFinalize(pCtx, pBlock);
2,209,506✔
4613
}
4614

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

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

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

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

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

4648
  SResultRowEntryInfo* pSResInfo = GET_RES_INFO(pSourceCtx);
×
4649
  SElapsedInfo*        pSBuf = GET_ROWCELL_INTERBUF(pSResInfo);
×
4650

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

4657
int32_t getHistogramInfoSize() {
320,713✔
4658
  return (int32_t)sizeof(SHistoFuncInfo) + HISTOGRAM_MAX_BINS_NUM * sizeof(SHistoFuncBin);
320,713✔
4659
}
4660

4661
bool getHistogramFuncEnv(SFunctionNode* UNUSED_PARAM(pFunc), SFuncExecEnv* pEnv) {
553,060✔
4662
  pEnv->calcMemSize = sizeof(SHistoFuncInfo) + HISTOGRAM_MAX_BINS_NUM * sizeof(SHistoFuncBin);
553,060✔
4663
  return true;
553,060✔
4664
}
4665

4666
static int8_t getHistogramBinType(char* binTypeStr) {
365,478✔
4667
  int8_t binType;
4668
  if (strcasecmp(binTypeStr, "user_input") == 0) {
365,478✔
4669
    binType = USER_INPUT_BIN;
203,268✔
4670
  } else if (strcasecmp(binTypeStr, "linear_bin") == 0) {
162,210✔
4671
    binType = LINEAR_BIN;
22,680✔
4672
  } else if (strcasecmp(binTypeStr, "log_bin") == 0) {
139,530✔
4673
    binType = LOG_BIN;
139,530✔
4674
  } else {
4675
    binType = UNKNOWN_BIN;
×
4676
  }
4677

4678
  return binType;
365,478✔
4679
}
4680

4681
static int32_t getHistogramBinDesc(SHistoFuncInfo* pInfo, char* binDescStr, int8_t binType, bool normalized) {
365,478✔
4682
  cJSON*  binDesc = cJSON_Parse(binDescStr);
365,478✔
4683
  int32_t numOfBins;
4684
  double* intervals;
4685
  if (cJSON_IsObject(binDesc)) { /* linaer/log bins */
365,478✔
4686
    int32_t numOfParams = cJSON_GetArraySize(binDesc);
162,210✔
4687
    int32_t startIndex;
4688
    if (numOfParams != 4) {
162,210✔
4689
      cJSON_Delete(binDesc);
×
4690
      return TSDB_CODE_FAILED;
×
4691
    }
4692

4693
    cJSON* start = cJSON_GetObjectItem(binDesc, "start");
162,210✔
4694
    cJSON* factor = cJSON_GetObjectItem(binDesc, "factor");
162,210✔
4695
    cJSON* width = cJSON_GetObjectItem(binDesc, "width");
162,210✔
4696
    cJSON* count = cJSON_GetObjectItem(binDesc, "count");
162,210✔
4697
    cJSON* infinity = cJSON_GetObjectItem(binDesc, "infinity");
162,210✔
4698

4699
    if (!cJSON_IsNumber(start) || !cJSON_IsNumber(count) || !cJSON_IsBool(infinity)) {
162,210✔
4700
      cJSON_Delete(binDesc);
×
4701
      return TSDB_CODE_FAILED;
×
4702
    }
4703

4704
    if (count->valueint <= 0 || count->valueint > 1000) {  // limit count to 1000
162,210✔
4705
      cJSON_Delete(binDesc);
×
4706
      return TSDB_CODE_FAILED;
×
4707
    }
4708

4709
    if (isinf(start->valuedouble) || (width != NULL && isinf(width->valuedouble)) ||
162,210✔
4710
        (factor != NULL && isinf(factor->valuedouble)) || (count != NULL && isinf(count->valuedouble))) {
162,210✔
4711
      cJSON_Delete(binDesc);
×
4712
      return TSDB_CODE_FAILED;
×
4713
    }
4714

4715
    int32_t counter = (int32_t)count->valueint;
162,210✔
4716
    if (infinity->valueint == false) {
162,210✔
4717
      startIndex = 0;
162,210✔
4718
      numOfBins = counter + 1;
162,210✔
4719
    } else {
UNCOV
4720
      startIndex = 1;
×
UNCOV
4721
      numOfBins = counter + 3;
×
4722
    }
4723

4724
    intervals = taosMemoryCalloc(numOfBins, sizeof(double));
162,210✔
4725
    if (NULL == intervals) {
162,210✔
4726
      cJSON_Delete(binDesc);
×
4727
      qError("histogram function out of memory");
×
4728
      return terrno;
×
4729
    }
4730
    if (cJSON_IsNumber(width) && factor == NULL && binType == LINEAR_BIN) {
162,210✔
4731
      // linear bin process
4732
      if (width->valuedouble == 0) {
22,680✔
4733
        taosMemoryFree(intervals);
×
4734
        cJSON_Delete(binDesc);
×
4735
        return TSDB_CODE_FAILED;
×
4736
      }
4737
      for (int i = 0; i < counter + 1; ++i) {
68,040✔
4738
        intervals[startIndex] = start->valuedouble + i * width->valuedouble;
45,360✔
4739
        if (isinf(intervals[startIndex])) {
45,360✔
4740
          taosMemoryFree(intervals);
×
4741
          cJSON_Delete(binDesc);
×
4742
          return TSDB_CODE_FAILED;
×
4743
        }
4744
        startIndex++;
45,360✔
4745
      }
4746
    } else if (cJSON_IsNumber(factor) && width == NULL && binType == LOG_BIN) {
139,530✔
4747
      // log bin process
4748
      if (start->valuedouble == 0) {
139,530✔
4749
        taosMemoryFree(intervals);
×
4750
        cJSON_Delete(binDesc);
×
4751
        return TSDB_CODE_FAILED;
×
4752
      }
4753
      if (factor->valuedouble < 0 || factor->valuedouble == 0 || factor->valuedouble == 1) {
139,530✔
4754
        taosMemoryFree(intervals);
×
4755
        cJSON_Delete(binDesc);
×
4756
        return TSDB_CODE_FAILED;
×
4757
      }
4758
      for (int i = 0; i < counter + 1; ++i) {
885,990✔
4759
        intervals[startIndex] = start->valuedouble * pow(factor->valuedouble, i * 1.0);
746,460✔
4760
        if (isinf(intervals[startIndex])) {
746,460✔
4761
          taosMemoryFree(intervals);
×
4762
          cJSON_Delete(binDesc);
×
4763
          return TSDB_CODE_FAILED;
×
4764
        }
4765
        startIndex++;
746,460✔
4766
      }
4767
    } else {
4768
      taosMemoryFree(intervals);
×
4769
      cJSON_Delete(binDesc);
×
4770
      return TSDB_CODE_FAILED;
×
4771
    }
4772

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

4823
  pInfo->numOfBins = numOfBins - 1;
365,478✔
4824
  pInfo->normalized = normalized;
365,478✔
4825
  for (int32_t i = 0; i < pInfo->numOfBins; ++i) {
1,514,020✔
4826
    pInfo->bins[i].lower = intervals[i] < intervals[i + 1] ? intervals[i] : intervals[i + 1];
1,148,542✔
4827
    pInfo->bins[i].upper = intervals[i + 1] > intervals[i] ? intervals[i + 1] : intervals[i];
1,148,542✔
4828
    pInfo->bins[i].count = 0;
1,148,542✔
4829
  }
4830

4831
  taosMemoryFree(intervals);
365,478✔
4832
  cJSON_Delete(binDesc);
365,478✔
4833

4834
  return TSDB_CODE_SUCCESS;
365,478✔
4835
}
4836

4837
int32_t histogramFunctionSetup(SqlFunctionCtx* pCtx, SResultRowEntryInfo* pResultInfo) {
365,478✔
4838
  if (pResultInfo->initialized) {
365,478✔
4839
    return TSDB_CODE_SUCCESS;
×
4840
  }
4841
  if (TSDB_CODE_SUCCESS != functionSetup(pCtx, pResultInfo)) {
365,478✔
4842
    return TSDB_CODE_FUNC_SETUP_ERROR;
×
4843
  }
4844

4845
  SHistoFuncInfo* pInfo = GET_ROWCELL_INTERBUF(pResultInfo);
365,478✔
4846
  pInfo->numOfBins = 0;
365,273✔
4847
  pInfo->totalCount = 0;
365,478✔
4848
  pInfo->normalized = 0;
365,478✔
4849

4850
  char* binTypeStr = taosStrndup(varDataVal(pCtx->param[1].param.pz), varDataLen(pCtx->param[1].param.pz));
365,478✔
4851
  if (binTypeStr == NULL) {
365,478✔
4852
    return terrno;
×
4853
  }
4854
  int8_t binType = getHistogramBinType(binTypeStr);
365,478✔
4855
  taosMemoryFree(binTypeStr);
365,478✔
4856

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

4876
  return TSDB_CODE_SUCCESS;
365,478✔
4877
}
4878

4879
static int32_t histogramFunctionImpl(SqlFunctionCtx* pCtx, bool isPartial) {
424,022✔
4880
  SHistoFuncInfo* pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
424,022✔
4881

4882
  SInputColumnInfoData* pInput = &pCtx->input;
424,022✔
4883
  SColumnInfoData*      pCol = pInput->pData[0];
424,022✔
4884

4885
  int32_t type = pInput->pData[0]->info.type;
424,022✔
4886

4887
  int32_t start = pInput->startRowIndex;
424,022✔
4888
  int32_t numOfRows = pInput->numOfRows;
424,022✔
4889

4890
  int32_t numOfElems = 0;
423,868✔
4891
  for (int32_t i = start; i < numOfRows + start; ++i) {
62,482,751✔
4892
    if (pCol->hasNull && colDataIsNull_f(pCol, i)) {
62,058,729✔
4893
      continue;
37,962,184✔
4894
    }
4895

4896
    numOfElems++;
24,095,887✔
4897

4898
    char*  data = colDataGetData(pCol, i);
24,095,887✔
4899
    double v;
4900
    GET_TYPED_DATA(v, double, type, data, typeGetTypeModFromColInfo(&pCol->info));
24,104,469✔
4901

4902
    for (int32_t k = 0; k < pInfo->numOfBins; ++k) {
66,173,658✔
4903
      if (v > pInfo->bins[k].lower && v <= pInfo->bins[k].upper) {
45,313,525✔
4904
        pInfo->bins[k].count++;
3,248,046✔
4905
        pInfo->totalCount++;
3,248,046✔
4906
        break;
3,248,046✔
4907
      }
4908
    }
4909
  }
4910

4911
  if (!isPartial) {
424,022✔
4912
    GET_RES_INFO(pCtx)->numOfRes = pInfo->numOfBins;
269,288✔
4913
  } else {
4914
    GET_RES_INFO(pCtx)->numOfRes = 1;
154,734✔
4915
  }
4916
  return TSDB_CODE_SUCCESS;
424,022✔
4917
}
4918

4919
int32_t histogramFunction(SqlFunctionCtx* pCtx) { return histogramFunctionImpl(pCtx, false); }
269,288✔
4920

4921
int32_t histogramFunctionPartial(SqlFunctionCtx* pCtx) { return histogramFunctionImpl(pCtx, true); }
154,734✔
4922

4923
static void histogramTransferInfo(SHistoFuncInfo* pInput, SHistoFuncInfo* pOutput) {
97,294✔
4924
  pOutput->normalized = pInput->normalized;
97,294✔
4925
  pOutput->numOfBins = pInput->numOfBins;
97,294✔
4926
  pOutput->totalCount += pInput->totalCount;
97,294✔
4927
  for (int32_t k = 0; k < pOutput->numOfBins; ++k) {
462,824✔
4928
    pOutput->bins[k].lower = pInput->bins[k].lower;
365,530✔
4929
    pOutput->bins[k].upper = pInput->bins[k].upper;
365,530✔
4930
    pOutput->bins[k].count += pInput->bins[k].count;
365,530✔
4931
  }
4932
}
97,294✔
4933

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

4941
  SHistoFuncInfo* pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
97,294✔
4942

4943
  int32_t start = pInput->startRowIndex;
97,294✔
4944

4945
  for (int32_t i = start; i < start + pInput->numOfRows; ++i) {
194,588✔
4946
    char*           data = colDataGetData(pCol, i);
97,294✔
4947
    SHistoFuncInfo* pInputInfo = (SHistoFuncInfo*)varDataVal(data);
97,294✔
4948
    histogramTransferInfo(pInputInfo, pInfo);
97,294✔
4949
  }
4950

4951
  SET_VAL(GET_RES_INFO(pCtx), pInfo->numOfBins, pInfo->numOfBins);
97,294✔
4952
  return TSDB_CODE_SUCCESS;
97,294✔
4953
}
4954

4955
int32_t histogramFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
357,250✔
4956
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
357,250✔
4957
  SHistoFuncInfo*      pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
357,250✔
4958
  int32_t              slotId = pCtx->pExpr->base.resSchema.slotId;
357,250✔
4959
  SColumnInfoData*     pCol = taosArrayGet(pBlock->pDataBlock, slotId);
357,250✔
4960
  int32_t              code = TSDB_CODE_SUCCESS;
357,250✔
4961

4962
  int32_t currentRow = pBlock->info.rows;
357,250✔
4963
  if (NULL == pCol) {
357,250✔
4964
    return TSDB_CODE_OUT_OF_RANGE;
×
4965
  }
4966

4967
  if (pInfo->normalized) {
357,250✔
4968
    for (int32_t k = 0; k < pResInfo->numOfRes; ++k) {
930,972✔
4969
      if (pInfo->totalCount != 0) {
722,634✔
4970
        pInfo->bins[k].percentage = pInfo->bins[k].count / (double)pInfo->totalCount;
14,376✔
4971
      } else {
4972
        pInfo->bins[k].percentage = 0;
708,258✔
4973
      }
4974
    }
4975
  }
4976

4977
  for (int32_t i = 0; i < pResInfo->numOfRes; ++i) {
1,481,108✔
4978
    int32_t len;
4979
    char    buf[512] = {0};
1,123,858✔
4980
    if (!pInfo->normalized) {
1,123,858✔
4981
      len = tsnprintf(varDataVal(buf), sizeof(buf) - VARSTR_HEADER_SIZE,
401,224✔
4982
                      "{\"lower_bin\":%g, \"upper_bin\":%g, \"count\":%" PRId64 "}", pInfo->bins[i].lower,
4983
                      pInfo->bins[i].upper, pInfo->bins[i].count);
4984
    } else {
4985
      len = tsnprintf(varDataVal(buf), sizeof(buf) - VARSTR_HEADER_SIZE,
722,634✔
4986
                      "{\"lower_bin\":%g, \"upper_bin\":%g, \"count\":%lf}", pInfo->bins[i].lower, pInfo->bins[i].upper,
4987
                      pInfo->bins[i].percentage);
4988
    }
4989
    varDataSetLen(buf, len);
1,123,858✔
4990
    code = colDataSetVal(pCol, currentRow, buf, false);
1,123,858✔
4991
    if (TSDB_CODE_SUCCESS != code) {
1,123,858✔
4992
      return code;
×
4993
    }
4994
    currentRow++;
1,123,858✔
4995
  }
4996

4997
  return code;
357,250✔
4998
}
4999

5000
int32_t histogramPartialFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
97,294✔
5001
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
97,294✔
5002
  SHistoFuncInfo*      pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
97,294✔
5003
  int32_t              resultBytes = getHistogramInfoSize();
97,294✔
5004
  char*                res = taosMemoryCalloc(resultBytes + VARSTR_HEADER_SIZE, sizeof(char));
97,294✔
5005

5006
  if (NULL == res) {
97,294✔
5007
    return terrno;
×
5008
  }
5009
  (void)memcpy(varDataVal(res), pInfo, resultBytes);
97,294✔
5010
  varDataSetLen(res, resultBytes);
97,294✔
5011

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

5021
_exit:
97,294✔
5022
  taosMemoryFree(res);
97,294✔
5023
  return code;
97,294✔
5024
}
5025

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

5030
  SResultRowEntryInfo* pSResInfo = GET_RES_INFO(pSourceCtx);
×
5031
  SHistoFuncInfo*      pSBuf = GET_ROWCELL_INTERBUF(pSResInfo);
×
5032

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

5039
int32_t getHLLInfoSize() { return (int32_t)sizeof(SHLLInfo); }
102,648✔
5040

5041
bool getHLLFuncEnv(SFunctionNode* UNUSED_PARAM(pFunc), SFuncExecEnv* pEnv) {
1,312,519✔
5042
  pEnv->calcMemSize = sizeof(SHLLInfo);
1,312,519✔
5043
  return true;
1,312,680✔
5044
}
5045

5046
static uint8_t hllCountNum(void* data, int32_t bytes, int32_t* buk) {
152,389,682✔
5047
  uint64_t hash = MurmurHash3_64(data, bytes);
152,389,682✔
5048
  int32_t  index = hash & HLL_BUCKET_MASK;
152,392,552✔
5049
  hash >>= HLL_BUCKET_BITS;
152,392,552✔
5050
  hash |= ((uint64_t)1 << HLL_DATA_BITS);
152,392,552✔
5051
  uint64_t bit = 1;
152,392,552✔
5052
  uint8_t  count = 1;
152,392,552✔
5053
  while ((hash & bit) == 0) {
313,249,508✔
5054
    count++;
160,856,956✔
5055
    bit <<= 1;
160,856,956✔
5056
  }
5057
  *buk = index;
152,392,552✔
5058
  return count;
152,394,288✔
5059
}
5060

5061
static void hllBucketHisto(uint8_t* buckets, int32_t* bucketHisto) {
2,866,979✔
5062
  uint64_t* word = (uint64_t*)buckets;
2,866,979✔
5063
  uint8_t*  bytes;
5064

5065
  for (int32_t j = 0; j < HLL_BUCKETS >> 3; j++) {
2,147,483,647✔
5066
    if (*word == 0) {
2,147,483,647✔
5067
      bucketHisto[0] += 8;
2,147,483,647✔
5068
    } else {
5069
      bytes = (uint8_t*)word;
21,641,893✔
5070
      bucketHisto[bytes[0]]++;
21,641,893✔
5071
      bucketHisto[bytes[1]]++;
33,371,209✔
5072
      bucketHisto[bytes[2]]++;
33,372,658✔
5073
      bucketHisto[bytes[3]]++;
33,373,785✔
5074
      bucketHisto[bytes[4]]++;
33,374,429✔
5075
      bucketHisto[bytes[5]]++;
33,374,429✔
5076
      bucketHisto[bytes[6]]++;
33,374,590✔
5077
      bucketHisto[bytes[7]]++;
33,374,912✔
5078
    }
5079
    word++;
2,147,483,647✔
5080
  }
5081
}
130,749✔
5082
static double hllTau(double x) {
2,867,301✔
5083
  if (x == 0. || x == 1.) return 0.;
2,867,301✔
5084
  double zPrime;
5085
  double y = 1.0;
×
5086
  double z = 1 - x;
×
5087
  do {
5088
    x = sqrt(x);
×
5089
    zPrime = z;
×
5090
    y *= 0.5;
×
5091
    z -= pow(1 - x, 2) * y;
×
5092
  } while (zPrime != z);
×
5093
  return z / 3;
×
5094
}
5095

5096
static double hllSigma(double x) {
2,867,140✔
5097
  if (x == 1.0) return INFINITY;
2,867,140✔
5098
  double zPrime;
5099
  double y = 1;
2,441,264✔
5100
  double z = x;
2,441,264✔
5101
  do {
5102
    x *= x;
46,886,711✔
5103
    zPrime = z;
46,886,711✔
5104
    z += x * y;
46,886,711✔
5105
    y += y;
46,886,711✔
5106
  } while (zPrime != z);
46,886,711✔
5107
  return z;
2,441,264✔
5108
}
5109

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

5117
  double z = m * hllTau((m - buckethisto[HLL_DATA_BITS + 1]) / (double)m);
2,867,301✔
5118
  for (int j = HLL_DATA_BITS; j >= 1; --j) {
146,224,301✔
5119
    z += buckethisto[j];
143,357,000✔
5120
    z *= 0.5;
143,357,161✔
5121
  }
5122

5123
  z += m * hllSigma(buckethisto[0] / (double)m);
2,867,301✔
5124
  double E = (double)llroundl(HLL_ALPHA_INF * m * m / z);
2,867,301✔
5125

5126
  return (uint64_t)E;
2,867,301✔
5127
}
5128

5129
int32_t hllFunction(SqlFunctionCtx* pCtx) {
2,946,299✔
5130
  SHLLInfo* pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
2,946,299✔
5131

5132
  SInputColumnInfoData* pInput = &pCtx->input;
2,947,097✔
5133
  SColumnInfoData*      pCol = pInput->pData[0];
2,947,104✔
5134

5135
  int32_t type = pCol->info.type;
2,946,743✔
5136
  int32_t bytes = pCol->info.bytes;
2,946,782✔
5137

5138
  int32_t start = pInput->startRowIndex;
2,946,782✔
5139
  int32_t numOfRows = pInput->numOfRows;
2,946,943✔
5140

5141
  int32_t numOfElems = 0;
2,946,260✔
5142
  if (IS_NULL_TYPE(type)) {
2,946,260✔
5143
    goto _hll_over;
59,830✔
5144
  }
5145

5146
  for (int32_t i = start; i < numOfRows + start; ++i) {
177,375,187✔
5147
    if (pCol->hasNull && colDataIsNull_s(pCol, i)) {
201,229,093✔
5148
      continue;
22,111,052✔
5149
    }
5150

5151
    numOfElems++;
152,378,846✔
5152

5153
    char* data = colDataGetData(pCol, i);
152,378,846✔
5154
    if (IS_VAR_DATA_TYPE(type)) {
152,396,822✔
5155
      if (IS_STR_DATA_BLOB(type)) {
25,479,759✔
5156
        bytes = blobDataLen(data);
1,939✔
5157
        data = blobDataVal(data);
×
5158
      } else {
5159
        bytes = varDataLen(data);
25,477,820✔
5160
        data = varDataVal(data);
25,477,498✔
5161
      }
5162
    }
5163

5164
    int32_t index = 0;
152,394,883✔
5165
    uint8_t count = hllCountNum(data, bytes, &index);
152,392,356✔
5166
    uint8_t oldcount = pInfo->buckets[index];
152,372,441✔
5167
    if (count > oldcount) {
152,377,705✔
5168
      pInfo->buckets[index] = count;
34,812,359✔
5169
    }
5170
  }
5171

5172
_hll_over:
2,882,790✔
5173
  pInfo->totalCount += numOfElems;
2,942,620✔
5174

5175
  if (pInfo->totalCount == 0 && !tsCountAlwaysReturnValue) {
2,946,943✔
5176
    SET_VAL(GET_RES_INFO(pCtx), 0, 1);
72,816✔
5177
  } else {
5178
    SET_VAL(GET_RES_INFO(pCtx), 1, 1);
2,874,288✔
5179
  }
5180

5181
  return TSDB_CODE_SUCCESS;
2,947,104✔
5182
}
5183

5184
static void hllTransferInfo(SHLLInfo* pInput, SHLLInfo* pOutput) {
102,648✔
5185
  for (int32_t k = 0; k < HLL_BUCKETS; ++k) {
1,664,633,510✔
5186
    if (pOutput->buckets[k] < pInput->buckets[k]) {
1,667,467,388✔
5187
      pOutput->buckets[k] = pInput->buckets[k];
5,880,884✔
5188
    }
5189
  }
5190
  pOutput->totalCount += pInput->totalCount;
4,652✔
5191
}
102,648✔
5192

5193
int32_t hllFunctionMerge(SqlFunctionCtx* pCtx) {
102,648✔
5194
  SInputColumnInfoData* pInput = &pCtx->input;
102,648✔
5195
  SColumnInfoData*      pCol = pInput->pData[0];
102,648✔
5196

5197
  if (IS_NULL_TYPE(pCol->info.type)) {
102,648✔
5198
    SET_VAL(GET_RES_INFO(pCtx), 0, 1);
×
5199
    return TSDB_CODE_SUCCESS;
×
5200
  }
5201

5202
  if (pCol->info.type != TSDB_DATA_TYPE_BINARY) {
102,648✔
5203
    return TSDB_CODE_SUCCESS;
×
5204
  }
5205

5206
  SHLLInfo* pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
102,648✔
5207

5208
  int32_t start = pInput->startRowIndex;
102,648✔
5209

5210
  for (int32_t i = start; i < start + pInput->numOfRows; ++i) {
205,296✔
5211
    if (colDataIsNull_s(pCol, i)) continue;
205,296✔
5212
    char*     data = colDataGetData(pCol, i);
102,648✔
5213
    SHLLInfo* pInputInfo = (SHLLInfo*)varDataVal(data);
102,648✔
5214
    hllTransferInfo(pInputInfo, pInfo);
102,648✔
5215
  }
5216

5217
  if (pInfo->totalCount == 0 && !tsCountAlwaysReturnValue) {
102,648✔
5218
    SET_VAL(GET_RES_INFO(pCtx), 0, 1);
288✔
5219
  } else {
5220
    SET_VAL(GET_RES_INFO(pCtx), 1, 1);
102,360✔
5221
  }
5222

5223
  return TSDB_CODE_SUCCESS;
102,648✔
5224
}
5225

5226
int32_t hllFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
2,867,301✔
5227
  SResultRowEntryInfo* pInfo = GET_RES_INFO(pCtx);
2,867,301✔
5228

5229
  SHLLInfo* pHllInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
2,867,301✔
5230
  pHllInfo->result = hllCountCnt(pHllInfo->buckets);
2,867,301✔
5231
  if (tsCountAlwaysReturnValue && pHllInfo->result == 0) {
2,867,301✔
5232
    pInfo->numOfRes = 1;
355,076✔
5233
  }
5234

5235
  return functionFinalize(pCtx, pBlock);
2,867,301✔
5236
}
5237

5238
int32_t hllPartialFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
102,648✔
5239
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
102,648✔
5240
  SHLLInfo*            pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
102,648✔
5241
  int32_t              resultBytes = getHLLInfoSize();
102,648✔
5242
  char*                res = taosMemoryCalloc(resultBytes + VARSTR_HEADER_SIZE, sizeof(char));
102,648✔
5243

5244
  if (NULL == res) {
102,648✔
5245
    return terrno;
×
5246
  }
5247
  (void)memcpy(varDataVal(res), pInfo, resultBytes);
102,648✔
5248
  varDataSetLen(res, resultBytes);
102,648✔
5249

5250
  int32_t          slotId = pCtx->pExpr->base.resSchema.slotId;
102,648✔
5251
  int32_t          code = TSDB_CODE_SUCCESS;
102,648✔
5252
  SColumnInfoData* pCol = taosArrayGet(pBlock->pDataBlock, slotId);
102,648✔
5253
  if (NULL == pCol) {
102,648✔
5254
    code = terrno;
×
5255
    goto _exit;
×
5256
  }
5257

5258
  code = colDataSetVal(pCol, pBlock->info.rows, res, false);
102,648✔
5259

5260
_exit:
102,648✔
5261
  taosMemoryFree(res);
102,648✔
5262
  return code;
102,648✔
5263
}
5264

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

5269
  SResultRowEntryInfo* pSResInfo = GET_RES_INFO(pSourceCtx);
×
5270
  SHLLInfo*            pSBuf = GET_ROWCELL_INTERBUF(pSResInfo);
×
5271

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

5278
bool getStateFuncEnv(SFunctionNode* UNUSED_PARAM(pFunc), SFuncExecEnv* pEnv) {
1,086,585✔
5279
  pEnv->calcMemSize = sizeof(SStateInfo);
1,086,585✔
5280
  return true;
1,086,585✔
5281
}
5282

5283
static int8_t getStateOpType(char* opStr) {
1,093,687✔
5284
  int8_t opType;
5285
  if (strncasecmp(opStr, "LT", 2) == 0) {
1,093,687✔
5286
    opType = STATE_OPER_LT;
242,134✔
5287
  } else if (strncasecmp(opStr, "GT", 2) == 0) {
851,553✔
5288
    opType = STATE_OPER_GT;
205,547✔
5289
  } else if (strncasecmp(opStr, "LE", 2) == 0) {
646,006✔
5290
    opType = STATE_OPER_LE;
125,284✔
5291
  } else if (strncasecmp(opStr, "GE", 2) == 0) {
520,722✔
5292
    opType = STATE_OPER_GE;
242,098✔
5293
  } else if (strncasecmp(opStr, "NE", 2) == 0) {
278,624✔
5294
    opType = STATE_OPER_NE;
135,532✔
5295
  } else if (strncasecmp(opStr, "EQ", 2) == 0) {
143,092✔
5296
    opType = STATE_OPER_EQ;
143,092✔
5297
  } else {
5298
    opType = STATE_OPER_INVALID;
×
5299
  }
5300

5301
  return opType;
1,093,687✔
5302
}
5303

5304
static bool checkStateOp(int8_t op, SColumnInfoData* pCol, int32_t index, SVariant param) {
37,382,315✔
5305
  char* data = colDataGetData(pCol, index);
37,382,315✔
5306
  switch (pCol->info.type) {
37,382,315✔
5307
    case TSDB_DATA_TYPE_TINYINT: {
2,073,722✔
5308
      int8_t v = *(int8_t*)data;
2,073,722✔
5309
      STATE_COMP(op, v, param);
2,073,722✔
5310
      break;
×
5311
    }
5312
    case TSDB_DATA_TYPE_UTINYINT: {
722,880✔
5313
      uint8_t v = *(uint8_t*)data;
722,880✔
5314
      STATE_COMP(op, v, param);
722,880✔
5315
      break;
×
5316
    }
5317
    case TSDB_DATA_TYPE_SMALLINT: {
3,211,724✔
5318
      int16_t v = *(int16_t*)data;
3,211,724✔
5319
      STATE_COMP(op, v, param);
3,211,724✔
5320
      break;
×
5321
    }
5322
    case TSDB_DATA_TYPE_USMALLINT: {
722,880✔
5323
      uint16_t v = *(uint16_t*)data;
722,880✔
5324
      STATE_COMP(op, v, param);
722,880✔
5325
      break;
×
5326
    }
5327
    case TSDB_DATA_TYPE_INT: {
1,438,524✔
5328
      int32_t v = *(int32_t*)data;
1,438,524✔
5329
      STATE_COMP(op, v, param);
1,438,524✔
5330
      break;
×
5331
    }
5332
    case TSDB_DATA_TYPE_UINT: {
722,880✔
5333
      uint32_t v = *(uint32_t*)data;
722,880✔
5334
      STATE_COMP(op, v, param);
722,880✔
5335
      break;
×
5336
    }
5337
    case TSDB_DATA_TYPE_BIGINT: {
22,816,131✔
5338
      int64_t v = *(int64_t*)data;
22,816,131✔
5339
      STATE_COMP(op, v, param);
22,816,131✔
5340
      break;
×
5341
    }
5342
    case TSDB_DATA_TYPE_UBIGINT: {
722,880✔
5343
      uint64_t v = *(uint64_t*)data;
722,880✔
5344
      STATE_COMP(op, v, param);
722,880✔
5345
      break;
×
5346
    }
5347
    case TSDB_DATA_TYPE_FLOAT: {
3,913,324✔
5348
      float v = *(float*)data;
3,913,324✔
5349
      STATE_COMP(op, v, param);
3,913,324✔
5350
      break;
×
5351
    }
5352
    case TSDB_DATA_TYPE_DOUBLE: {
1,037,370✔
5353
      double v = *(double*)data;
1,037,370✔
5354
      STATE_COMP(op, v, param);
1,037,370✔
5355
      break;
×
5356
    }
5357
    default: {
×
5358
      return false;
×
5359
    }
5360
  }
5361
  return false;
×
5362
}
5363

5364
int32_t stateCountFunction(SqlFunctionCtx* pCtx) {
110,330✔
5365
  int32_t              code = TSDB_CODE_SUCCESS;
110,330✔
5366
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
110,330✔
5367
  SStateInfo*          pInfo = GET_ROWCELL_INTERBUF(pResInfo);
110,330✔
5368

5369
  SInputColumnInfoData* pInput = &pCtx->input;
110,330✔
5370
  TSKEY*                tsList = (int64_t*)pInput->pPTS->pData;
110,330✔
5371

5372
  SColumnInfoData* pInputCol = pInput->pData[0];
110,330✔
5373

5374
  int32_t          numOfElems = 0;
110,330✔
5375
  SColumnInfoData* pOutput = (SColumnInfoData*)pCtx->pOutput;
110,330✔
5376

5377
  int8_t op = getStateOpType(varDataVal(pCtx->param[1].param.pz));
110,330✔
5378
  if (STATE_OPER_INVALID == op) {
110,330✔
5379
    return 0;
×
5380
  }
5381

5382
  for (int32_t i = pInput->startRowIndex; i < pInput->numOfRows + pInput->startRowIndex; i += 1) {
14,470,366✔
5383
    if (pInfo->isPrevTsSet == true && tsList[i] == pInfo->prevTs) {
14,360,036✔
5384
      return TSDB_CODE_FUNC_DUP_TIMESTAMP;
×
5385
    } else {
5386
      pInfo->prevTs = tsList[i];
14,360,036✔
5387
    }
5388

5389
    pInfo->isPrevTsSet = true;
14,360,036✔
5390
    numOfElems++;
14,360,036✔
5391

5392
    if (colDataIsNull_f(pInputCol, i)) {
14,360,036✔
5393
      colDataSetNULL(pOutput, i);
78,780✔
5394
      // handle selectivity
5395
      if (pCtx->subsidiaries.num > 0) {
78,780✔
5396
        code = appendSelectivityValue(pCtx, i, pCtx->offset + numOfElems - 1);
4,545✔
5397
        if (TSDB_CODE_SUCCESS != code) {
4,545✔
5398
          return code;
×
5399
        }
5400
      }
5401
      continue;
78,780✔
5402
    }
5403

5404
    bool ret = checkStateOp(op, pInputCol, i, pCtx->param[2].param);
14,281,256✔
5405

5406
    int64_t output = -1;
14,281,256✔
5407
    if (ret) {
14,281,256✔
5408
      output = ++pInfo->count;
6,817,217✔
5409
    } else {
5410
      pInfo->count = 0;
7,464,039✔
5411
    }
5412
    code = colDataSetVal(pOutput, pCtx->offset + numOfElems - 1, (char*)&output, false);
14,281,256✔
5413
    if (TSDB_CODE_SUCCESS != code) {
14,281,256✔
5414
      return code;
×
5415
    }
5416

5417
    // handle selectivity
5418
    if (pCtx->subsidiaries.num > 0) {
14,281,256✔
5419
      code = appendSelectivityValue(pCtx, i, pCtx->offset + numOfElems - 1);
54,540✔
5420
      if (TSDB_CODE_SUCCESS != code) {
54,540✔
5421
        return code;
×
5422
      }
5423
    }
5424
  }
5425

5426
  pResInfo->numOfRes = numOfElems;
110,330✔
5427
  return TSDB_CODE_SUCCESS;
110,330✔
5428
}
5429

5430
int32_t stateDurationFunction(SqlFunctionCtx* pCtx) {
983,357✔
5431
  int32_t              code = TSDB_CODE_SUCCESS;
983,357✔
5432
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
983,357✔
5433
  SStateInfo*          pInfo = GET_ROWCELL_INTERBUF(pResInfo);
983,357✔
5434

5435
  SInputColumnInfoData* pInput = &pCtx->input;
983,357✔
5436
  TSKEY*                tsList = (int64_t*)pInput->pPTS->pData;
983,357✔
5437

5438
  SColumnInfoData* pInputCol = pInput->pData[0];
983,357✔
5439

5440
  int32_t          numOfElems = 0;
983,357✔
5441
  SColumnInfoData* pOutput = (SColumnInfoData*)pCtx->pOutput;
983,357✔
5442

5443
  // TODO: process timeUnit for different db precisions
5444
  int32_t timeUnit = 1;
983,357✔
5445
  if (pCtx->numOfParams == 5) {  // TODO: param number incorrect
983,357✔
5446
    timeUnit = pCtx->param[3].param.i;
737,300✔
5447
  }
5448

5449
  int8_t op = getStateOpType(varDataVal(pCtx->param[1].param.pz));
983,357✔
5450
  if (STATE_OPER_INVALID == op) {
983,357✔
5451
    return TSDB_CODE_INVALID_PARA;
×
5452
  }
5453

5454
  for (int32_t i = pInput->startRowIndex; i < pInput->numOfRows + pInput->startRowIndex; i += 1) {
43,344,648✔
5455
    if (pInfo->isPrevTsSet == true && tsList[i] == pInfo->prevTs) {
42,361,291✔
5456
      return TSDB_CODE_FUNC_DUP_TIMESTAMP;
×
5457
    } else {
5458
      pInfo->prevTs = tsList[i];
42,361,088✔
5459
    }
5460

5461
    pInfo->isPrevTsSet = true;
42,361,291✔
5462
    numOfElems++;
42,361,088✔
5463

5464
    if (colDataIsNull_f(pInputCol, i)) {
42,361,088✔
5465
      colDataSetNULL(pOutput, i);
19,260,232✔
5466
      // handle selectivity
5467
      if (pCtx->subsidiaries.num > 0) {
19,260,232✔
5468
        code = appendSelectivityValue(pCtx, i, pCtx->offset + numOfElems - 1);
7,329✔
5469
        if (TSDB_CODE_SUCCESS != code) {
7,329✔
5470
          return code;
×
5471
        }
5472
      }
5473
      continue;
19,260,232✔
5474
    }
5475

5476
    bool    ret = checkStateOp(op, pInputCol, i, pCtx->param[2].param);
23,101,059✔
5477
    int64_t output = -1;
23,101,059✔
5478
    if (ret) {
23,101,059✔
5479
      if (pInfo->durationStart == 0) {
12,234,366✔
5480
        output = 0;
5,259,166✔
5481
        pInfo->durationStart = tsList[i];
5,259,166✔
5482
      } else {
5483
        output = (tsList[i] - pInfo->durationStart) / timeUnit;
6,975,200✔
5484
      }
5485
    } else {
5486
      pInfo->durationStart = 0;
10,866,693✔
5487
    }
5488
    code = colDataSetVal(pOutput, pCtx->offset + numOfElems - 1, (char*)&output, false);
23,101,059✔
5489
    if (TSDB_CODE_SUCCESS != code) {
23,101,059✔
5490
      return code;
×
5491
    }
5492

5493
    // handle selectivity
5494
    if (pCtx->subsidiaries.num > 0) {
23,101,059✔
5495
      code = appendSelectivityValue(pCtx, i, pCtx->offset + numOfElems - 1);
87,948✔
5496
      if (TSDB_CODE_SUCCESS != code) {
87,948✔
5497
        return code;
×
5498
      }
5499
    }
5500
  }
5501

5502
  pResInfo->numOfRes = numOfElems;
983,357✔
5503
  return TSDB_CODE_SUCCESS;
983,357✔
5504
}
5505

5506
bool getCsumFuncEnv(SFunctionNode* UNUSED_PARAM(pFunc), SFuncExecEnv* pEnv) {
365,752✔
5507
  pEnv->calcMemSize = sizeof(SSumRes);
365,752✔
5508
  return true;
365,752✔
5509
}
5510

5511
int32_t csumFunction(SqlFunctionCtx* pCtx) {
437,514✔
5512
  int32_t              code = TSDB_CODE_SUCCESS;
437,514✔
5513
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
437,514✔
5514
  SSumRes*             pSumRes = GET_ROWCELL_INTERBUF(pResInfo);
437,302✔
5515

5516
  SInputColumnInfoData* pInput = &pCtx->input;
437,302✔
5517
  TSKEY*                tsList = (int64_t*)pInput->pPTS->pData;
437,302✔
5518

5519
  SColumnInfoData* pInputCol = pInput->pData[0];
437,302✔
5520
  SColumnInfoData* pOutput = (SColumnInfoData*)pCtx->pOutput;
437,302✔
5521

5522
  int32_t numOfElems = 0;
437,514✔
5523
  int32_t type = pInputCol->info.type;
437,514✔
5524
  int32_t startOffset = pCtx->offset;
437,302✔
5525
  for (int32_t i = pInput->startRowIndex; i < pInput->numOfRows + pInput->startRowIndex; i += 1) {
49,789,447✔
5526
    if (pSumRes->isPrevTsSet == true && tsList[i] == pSumRes->prevTs) {
49,352,423✔
5527
      return TSDB_CODE_FUNC_DUP_TIMESTAMP;
8,334✔
5528
    } else {
5529
      pSumRes->prevTs = tsList[i];
49,344,301✔
5530
    }
5531
    pSumRes->isPrevTsSet = true;
49,344,513✔
5532

5533
    int32_t pos = startOffset + numOfElems;
49,345,361✔
5534
    if (colDataIsNull_f(pInputCol, i)) {
49,345,361✔
5535
      // colDataSetNULL(pOutput, i);
5536
      continue;
43,865,916✔
5537
    }
5538

5539
    char* data = colDataGetData(pInputCol, i);
5,486,229✔
5540
    if (IS_SIGNED_NUMERIC_TYPE(type)) {
10,506,990✔
5541
      int64_t v;
5542
      GET_TYPED_DATA(v, int64_t, type, data, typeGetTypeModFromColInfo(&pInputCol->info));
5,020,761✔
5543
      pSumRes->isum += v;
5,020,761✔
5544
      code = colDataSetVal(pOutput, pos, (char*)&pSumRes->isum, false);
5,020,761✔
5545
      if (TSDB_CODE_SUCCESS != code) {
5,020,761✔
5546
        return code;
×
5547
      }
5548
    } else if (IS_UNSIGNED_NUMERIC_TYPE(type)) {
552,712✔
5549
      uint64_t v;
5550
      GET_TYPED_DATA(v, uint64_t, type, data, typeGetTypeModFromColInfo(&pInputCol->info));
87,244✔
5551
      pSumRes->usum += v;
87,244✔
5552
      code = colDataSetVal(pOutput, pos, (char*)&pSumRes->usum, false);
87,244✔
5553
      if (TSDB_CODE_SUCCESS != code) {
87,244✔
5554
        return code;
×
5555
      }
5556
    } else if (IS_FLOAT_TYPE(type)) {
378,224✔
5557
      double v;
5558
      GET_TYPED_DATA(v, double, type, data, typeGetTypeModFromColInfo(&pInputCol->info));
378,224✔
5559
      pSumRes->dsum += v;
378,224✔
5560
      // check for overflow
5561
      if (isinf(pSumRes->dsum) || isnan(pSumRes->dsum)) {
378,224✔
5562
        colDataSetNULL(pOutput, pos);
1,028✔
5563
      } else {
5564
        code = colDataSetVal(pOutput, pos, (char*)&pSumRes->dsum, false);
377,196✔
5565
        if (TSDB_CODE_SUCCESS != code) {
377,196✔
5566
          return code;
×
5567
        }
5568
      }
5569
    }
5570

5571
    // handle selectivity
5572
    if (pCtx->subsidiaries.num > 0) {
5,486,229✔
5573
      code = appendSelectivityValue(pCtx, i, pos);
23,766✔
5574
      if (TSDB_CODE_SUCCESS != code) {
23,766✔
5575
        return code;
×
5576
      }
5577
    }
5578

5579
    numOfElems++;
5,486,229✔
5580
  }
5581

5582
  pResInfo->numOfRes = numOfElems;
429,180✔
5583
  return TSDB_CODE_SUCCESS;
429,180✔
5584
}
5585

5586
bool getMavgFuncEnv(SFunctionNode* UNUSED_PARAM(pFunc), SFuncExecEnv* pEnv) {
162,740✔
5587
  pEnv->calcMemSize = sizeof(SMavgInfo) + MAVG_MAX_POINTS_NUM * sizeof(double);
162,740✔
5588
  return true;
162,740✔
5589
}
5590

5591
int32_t mavgFunctionSetup(SqlFunctionCtx* pCtx, SResultRowEntryInfo* pResultInfo) {
396,404✔
5592
  if (pResultInfo->initialized) {
396,404✔
5593
    return TSDB_CODE_SUCCESS;
147,257✔
5594
  }
5595
  if (TSDB_CODE_SUCCESS != functionSetup(pCtx, pResultInfo)) {
249,147✔
5596
    return TSDB_CODE_FUNC_SETUP_ERROR;
×
5597
  }
5598

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

5610
  return TSDB_CODE_SUCCESS;
249,147✔
5611
}
5612

5613
int32_t mavgFunction(SqlFunctionCtx* pCtx) {
233,664✔
5614
  int32_t              code = TSDB_CODE_SUCCESS;
233,664✔
5615
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
233,664✔
5616
  SMavgInfo*           pInfo = GET_ROWCELL_INTERBUF(pResInfo);
233,664✔
5617

5618
  SInputColumnInfoData* pInput = &pCtx->input;
233,664✔
5619
  TSKEY*                tsList = (int64_t*)pInput->pPTS->pData;
233,664✔
5620

5621
  SColumnInfoData* pInputCol = pInput->pData[0];
233,664✔
5622
  SColumnInfoData* pTsOutput = pCtx->pTsOutput;
233,664✔
5623
  SColumnInfoData* pOutput = (SColumnInfoData*)pCtx->pOutput;
233,664✔
5624

5625
  int32_t numOfElems = 0;
233,664✔
5626
  int32_t type = pInputCol->info.type;
233,664✔
5627
  int32_t startOffset = pCtx->offset;
233,664✔
5628
  for (int32_t i = pInput->startRowIndex; i < pInput->numOfRows + pInput->startRowIndex; i += 1) {
27,359,572✔
5629
    if (pInfo->isPrevTsSet == true && tsList[i] == pInfo->prevTs) {
27,125,908✔
5630
      return TSDB_CODE_FUNC_DUP_TIMESTAMP;
×
5631
    } else {
5632
      pInfo->prevTs = tsList[i];
27,125,908✔
5633
    }
5634
    pInfo->isPrevTsSet = true;
27,125,908✔
5635

5636
    int32_t pos = startOffset + numOfElems;
27,125,908✔
5637
    if (colDataIsNull_f(pInputCol, i)) {
27,125,908✔
5638
      // colDataSetNULL(pOutput, i);
5639
      continue;
13,742,535✔
5640
    }
5641

5642
    char*  data = colDataGetData(pInputCol, i);
13,383,373✔
5643
    double v;
5644
    GET_TYPED_DATA(v, double, type, data, typeGetTypeModFromColInfo(&pInputCol->info));
13,383,373✔
5645

5646
    if (!pInfo->pointsMeet && (pInfo->pos < pInfo->numOfPoints - 1)) {
13,383,373✔
5647
      pInfo->points[pInfo->pos] = v;
13,106,590✔
5648
      pInfo->sum += v;
13,106,590✔
5649
    } else {
5650
      if (!pInfo->pointsMeet && (pInfo->pos == pInfo->numOfPoints - 1)) {
276,783✔
5651
        pInfo->sum += v;
89,587✔
5652
        pInfo->pointsMeet = true;
89,587✔
5653
      } else {
5654
        pInfo->sum = pInfo->sum + v - pInfo->points[pInfo->pos];
187,196✔
5655
      }
5656

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

5669
      // handle selectivity
5670
      if (pCtx->subsidiaries.num > 0) {
276,783✔
5671
        code = appendSelectivityValue(pCtx, i, pos);
35,630✔
5672
        if (TSDB_CODE_SUCCESS != code) {
35,630✔
5673
          return code;
×
5674
        }
5675
      }
5676

5677
      numOfElems++;
276,783✔
5678
    }
5679

5680
    pInfo->pos++;
13,383,373✔
5681
    if (pInfo->pos == pInfo->numOfPoints) {
13,383,373✔
5682
      pInfo->pos = 0;
136,496✔
5683
    }
5684
  }
5685

5686
  pResInfo->numOfRes = numOfElems;
233,664✔
5687
  return TSDB_CODE_SUCCESS;
233,664✔
5688
}
5689

5690
static SSampleInfo* getSampleOutputInfo(SqlFunctionCtx* pCtx) {
2,973,521✔
5691
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
2,973,521✔
5692
  SSampleInfo*         pInfo = GET_ROWCELL_INTERBUF(pResInfo);
2,973,521✔
5693

5694
  pInfo->data = (char*)pInfo + sizeof(SSampleInfo);
2,973,521✔
5695
  pInfo->tuplePos = (STuplePos*)((char*)pInfo + sizeof(SSampleInfo) + pInfo->samples * pInfo->colBytes);
2,973,521✔
5696

5697
  return pInfo;
2,973,521✔
5698
}
5699

5700
bool getSampleFuncEnv(SFunctionNode* pFunc, SFuncExecEnv* pEnv) {
432,813✔
5701
  SColumnNode* pCol = (SColumnNode*)nodesListGetNode(pFunc->pParameterList, 0);
432,813✔
5702
  SValueNode*  pVal = (SValueNode*)nodesListGetNode(pFunc->pParameterList, 1);
432,610✔
5703
  int32_t      numOfSamples = pVal->datum.i;
432,488✔
5704
  pEnv->calcMemSize = sizeof(SSampleInfo) + numOfSamples * (pCol->node.resType.bytes + sizeof(STuplePos));
432,283✔
5705
  return true;
432,405✔
5706
}
5707

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

5716
  taosSeedRand(taosSafeRand());
1,434,838✔
5717

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

5729
  return TSDB_CODE_SUCCESS;
1,434,838✔
5730
}
5731

5732
static void sampleAssignResult(SSampleInfo* pInfo, char* data, int32_t index) {
30,177,941✔
5733
  assignVal(pInfo->data + index * pInfo->colBytes, data, pInfo->colBytes, pInfo->colType);
30,177,941✔
5734
}
30,178,351✔
5735

5736
static int32_t doReservoirSample(SqlFunctionCtx* pCtx, SSampleInfo* pInfo, char* data, int32_t index) {
32,897,236✔
5737
  pInfo->totalPoints++;
32,897,236✔
5738
  if (pInfo->numSampled < pInfo->samples) {
32,897,236✔
5739
    sampleAssignResult(pInfo, data, pInfo->numSampled);
25,912,466✔
5740
    if (pCtx->subsidiaries.num > 0) {
25,912,466✔
5741
      int32_t code = saveTupleData(pCtx, index, pCtx->pSrcBlock, &pInfo->tuplePos[pInfo->numSampled]);
1,029,640✔
5742
      if (code != TSDB_CODE_SUCCESS) {
1,029,640✔
5743
        return code;
×
5744
      }
5745
    }
5746
    pInfo->numSampled++;
25,912,466✔
5747
  } else {
5748
    int32_t j = taosRand() % (pInfo->totalPoints);
6,984,770✔
5749
    if (j < pInfo->samples) {
6,984,770✔
5750
      sampleAssignResult(pInfo, data, j);
4,266,295✔
5751
      if (pCtx->subsidiaries.num > 0) {
4,266,295✔
5752
        int32_t code = updateTupleData(pCtx, index, pCtx->pSrcBlock, &pInfo->tuplePos[j]);
31,763✔
5753
        if (code != TSDB_CODE_SUCCESS) {
27,048✔
5754
          return code;
×
5755
        }
5756
      }
5757
    }
5758
  }
5759

5760
  return TSDB_CODE_SUCCESS;
32,892,521✔
5761
}
5762

5763
int32_t sampleFunction(SqlFunctionCtx* pCtx) {
1,538,683✔
5764
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
1,538,683✔
5765
  SSampleInfo*         pInfo = getSampleOutputInfo(pCtx);
1,538,683✔
5766

5767
  SInputColumnInfoData* pInput = &pCtx->input;
1,538,683✔
5768

5769
  SColumnInfoData* pInputCol = pInput->pData[0];
1,538,683✔
5770
  for (int32_t i = pInput->startRowIndex; i < pInput->numOfRows + pInput->startRowIndex; i += 1) {
54,484,623✔
5771
    if (colDataIsNull_s(pInputCol, i)) {
105,892,700✔
5772
      continue;
20,049,524✔
5773
    }
5774

5775
    char*   data = colDataGetData(pInputCol, i);
32,897,031✔
5776
    int32_t code = doReservoirSample(pCtx, pInfo, data, i);
32,897,236✔
5777
    if (code != TSDB_CODE_SUCCESS) {
32,896,416✔
5778
      return code;
×
5779
    }
5780
  }
5781

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

5790
  SET_VAL(pResInfo, pInfo->numSampled, pInfo->numSampled);
1,538,683✔
5791
  return TSDB_CODE_SUCCESS;
1,538,683✔
5792
}
5793

5794
int32_t sampleFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
1,434,838✔
5795
  int32_t              code = TSDB_CODE_SUCCESS;
1,434,838✔
5796
  SResultRowEntryInfo* pEntryInfo = GET_RES_INFO(pCtx);
1,434,838✔
5797

5798
  SSampleInfo* pInfo = getSampleOutputInfo(pCtx);
1,434,838✔
5799
  pEntryInfo->complete = true;
1,434,838✔
5800

5801
  int32_t          slotId = pCtx->pExpr->base.resSchema.slotId;
1,434,838✔
5802
  SColumnInfoData* pCol = taosArrayGet(pBlock->pDataBlock, slotId);
1,434,838✔
5803
  if (NULL == pCol) {
1,434,838✔
5804
    return TSDB_CODE_OUT_OF_RANGE;
×
5805
  }
5806

5807
  int32_t currentRow = pBlock->info.rows;
1,434,838✔
5808
  if (pInfo->numSampled == 0) {
1,434,838✔
5809
    colDataSetNULL(pCol, currentRow);
155,545✔
5810
    code = setSelectivityValue(pCtx, pBlock, &pInfo->nullTuplePos, currentRow);
155,545✔
5811
    return code;
155,545✔
5812
  }
5813
  for (int32_t i = 0; i < pInfo->numSampled; ++i) {
27,191,759✔
5814
    code = colDataSetVal(pCol, currentRow + i, pInfo->data + i * pInfo->colBytes, false);
25,912,466✔
5815
    if (TSDB_CODE_SUCCESS != code) {
25,912,466✔
5816
      return code;
×
5817
    }
5818
    code = setSelectivityValue(pCtx, pBlock, &pInfo->tuplePos[i], currentRow + i);
25,912,466✔
5819
    if (TSDB_CODE_SUCCESS != code) {
25,912,466✔
5820
      return code;
×
5821
    }
5822
  }
5823

5824
  return code;
1,279,293✔
5825
}
5826

5827
bool getTailFuncEnv(SFunctionNode* pFunc, SFuncExecEnv* pEnv) {
×
5828
#if 0
5829
  SColumnNode* pCol = (SColumnNode*)nodesListGetNode(pFunc->pParameterList, 0);
5830
  SValueNode*  pVal = (SValueNode*)nodesListGetNode(pFunc->pParameterList, 1);
5831
  int32_t      numOfPoints = pVal->datum.i;
5832
  pEnv->calcMemSize = sizeof(STailInfo) + numOfPoints * (POINTER_BYTES + sizeof(STailItem) + pCol->node.resType.bytes);
5833
#endif
5834
  return true;
×
5835
}
5836

5837
int32_t tailFunctionSetup(SqlFunctionCtx* pCtx, SResultRowEntryInfo* pResultInfo) {
×
5838
#if 0
5839
  if (!functionSetup(pCtx, pResultInfo)) {
5840
    return false;
5841
  }
5842

5843
  STailInfo* pInfo = GET_ROWCELL_INTERBUF(pResultInfo);
5844
  pInfo->numAdded = 0;
5845
  pInfo->numOfPoints = pCtx->param[1].param.i;
5846
  if (pCtx->numOfParams == 4) {
5847
    pInfo->offset = pCtx->param[2].param.i;
5848
  } else {
5849
    pInfo->offset = 0;
5850
  }
5851
  pInfo->colType = pCtx->resDataInfo.type;
5852
  pInfo->colBytes = pCtx->resDataInfo.bytes;
5853
  if ((pInfo->numOfPoints < 1 || pInfo->numOfPoints > TAIL_MAX_POINTS_NUM) ||
5854
      (pInfo->numOfPoints < 0 || pInfo->numOfPoints > TAIL_MAX_OFFSET)) {
5855
    return false;
5856
  }
5857

5858
  pInfo->pItems = (STailItem**)((char*)pInfo + sizeof(STailInfo));
5859
  char* pItem = (char*)pInfo->pItems + pInfo->numOfPoints * POINTER_BYTES;
5860

5861
  size_t unitSize = sizeof(STailItem) + pInfo->colBytes;
5862
  for (int32_t i = 0; i < pInfo->numOfPoints; ++i) {
5863
    pInfo->pItems[i] = (STailItem*)(pItem + i * unitSize);
5864
    pInfo->pItems[i]->isNull = false;
5865
  }
5866
#endif
5867

5868
  return TSDB_CODE_SUCCESS;
×
5869
}
5870

5871
static void tailAssignResult(STailItem* pItem, char* data, int32_t colBytes, TSKEY ts, bool isNull) {
×
5872
#if 0
5873
  pItem->timestamp = ts;
5874
  if (isNull) {
5875
    pItem->isNull = true;
5876
  } else {
5877
    pItem->isNull = false;
5878
    memcpy(pItem->data, data, colBytes);
5879
  }
5880
#endif
5881
}
×
5882

5883
#if 0
5884
static int32_t tailCompFn(const void* p1, const void* p2, const void* param) {
5885
  STailItem* d1 = *(STailItem**)p1;
5886
  STailItem* d2 = *(STailItem**)p2;
5887
  return compareInt64Val(&d1->timestamp, &d2->timestamp);
5888
}
5889

5890
static void doTailAdd(STailInfo* pInfo, char* data, TSKEY ts, bool isNull) {
5891
  STailItem** pList = pInfo->pItems;
5892
  if (pInfo->numAdded < pInfo->numOfPoints) {
5893
    tailAssignResult(pList[pInfo->numAdded], data, pInfo->colBytes, ts, isNull);
5894
    taosheapsort((void*)pList, sizeof(STailItem**), pInfo->numAdded + 1, NULL, tailCompFn, 0);
5895
    pInfo->numAdded++;
5896
  } else if (pList[0]->timestamp < ts) {
5897
    tailAssignResult(pList[0], data, pInfo->colBytes, ts, isNull);
5898
    taosheapadjust((void*)pList, sizeof(STailItem**), 0, pInfo->numOfPoints - 1, NULL, tailCompFn, NULL, 0);
5899
  }
5900
}
5901
#endif
5902

5903
int32_t tailFunction(SqlFunctionCtx* pCtx) {
×
5904
#if 0
5905
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
5906
  STailInfo*           pInfo = GET_ROWCELL_INTERBUF(pResInfo);
5907

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

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

5914
  int32_t startOffset = pCtx->offset;
5915
  if (pInfo->offset >= pInput->numOfRows) {
5916
    return 0;
5917
  } else {
5918
    pInfo->numOfPoints = TMIN(pInfo->numOfPoints, pInput->numOfRows - pInfo->offset);
5919
  }
5920
  for (int32_t i = pInput->startRowIndex; i < pInput->numOfRows + pInput->startRowIndex - pInfo->offset; i += 1) {
5921
    char* data = colDataGetData(pInputCol, i);
5922
    doTailAdd(pInfo, data, tsList[i], colDataIsNull_s(pInputCol, i));
5923
  }
5924

5925
  taosqsort(pInfo->pItems, pInfo->numOfPoints, POINTER_BYTES, NULL, tailCompFn);
5926

5927
  for (int32_t i = 0; i < pInfo->numOfPoints; ++i) {
5928
    int32_t    pos = startOffset + i;
5929
    STailItem* pItem = pInfo->pItems[i];
5930
    if (pItem->isNull) {
5931
      colDataSetNULL(pOutput, pos);
5932
    } else {
5933
      colDataSetVal(pOutput, pos, pItem->data, false);
5934
    }
5935
  }
5936

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

5942
int32_t tailFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
×
5943
#if 0
5944
  SResultRowEntryInfo* pEntryInfo = GET_RES_INFO(pCtx);
5945
  STailInfo*           pInfo = GET_ROWCELL_INTERBUF(pEntryInfo);
5946
  pEntryInfo->complete = true;
5947

5948
  int32_t type = pCtx->input.pData[0]->info.type;
5949
  int32_t slotId = pCtx->pExpr->base.resSchema.slotId;
5950

5951
  SColumnInfoData* pCol = taosArrayGet(pBlock->pDataBlock, slotId);
5952

5953
  // todo assign the tag value and the corresponding row data
5954
  int32_t currentRow = pBlock->info.rows;
5955
  for (int32_t i = 0; i < pEntryInfo->numOfRes; ++i) {
5956
    STailItem* pItem = pInfo->pItems[i];
5957
    colDataSetVal(pCol, currentRow, pItem->data, false);
5958
    currentRow += 1;
5959
  }
5960

5961
  return pEntryInfo->numOfRes;
5962
#endif
5963
  return 0;
×
5964
}
5965

5966
bool getUniqueFuncEnv(SFunctionNode* pFunc, SFuncExecEnv* pEnv) {
×
5967
#if 0
5968
  pEnv->calcMemSize = sizeof(SUniqueInfo) + UNIQUE_MAX_RESULT_SIZE;
5969
#endif
5970
  return true;
×
5971
}
5972

5973
int32_t uniqueFunctionSetup(SqlFunctionCtx* pCtx, SResultRowEntryInfo* pResInfo) {
×
5974
#if 0
5975
  if (!functionSetup(pCtx, pResInfo)) {
5976
    return false;
5977
  }
5978

5979
  SUniqueInfo* pInfo = GET_ROWCELL_INTERBUF(pResInfo);
5980
  pInfo->numOfPoints = 0;
5981
  pInfo->colType = pCtx->resDataInfo.type;
5982
  pInfo->colBytes = pCtx->resDataInfo.bytes;
5983
  if (pInfo->pHash != NULL) {
5984
    taosHashClear(pInfo->pHash);
5985
  } else {
5986
    pInfo->pHash = taosHashInit(64, taosGetDefaultHashFunction(TSDB_DATA_TYPE_BINARY), true, HASH_NO_LOCK);
5987
  }
5988
#endif
5989
  return TSDB_CODE_SUCCESS;
×
5990
}
5991

5992
#if 0
5993
static void doUniqueAdd(SUniqueInfo* pInfo, char* data, TSKEY ts, bool isNull) {
5994
  // handle null elements
5995
  if (isNull == true) {
5996
    int32_t      size = sizeof(SUniqueItem) + pInfo->colBytes;
5997
    SUniqueItem* pItem = (SUniqueItem*)(pInfo->pItems + pInfo->numOfPoints * size);
5998
    if (pInfo->hasNull == false && pItem->isNull == false) {
5999
      pItem->timestamp = ts;
6000
      pItem->isNull = true;
6001
      pInfo->numOfPoints++;
6002
      pInfo->hasNull = true;
6003
    } else if (pItem->timestamp > ts && pItem->isNull == true) {
6004
      pItem->timestamp = ts;
6005
    }
6006
    return;
6007
  }
6008

6009
  int32_t      hashKeyBytes = IS_VAR_DATA_TYPE(pInfo->colType) ? varDataTLen(data) : pInfo->colBytes;
6010
  SUniqueItem* pHashItem = taosHashGet(pInfo->pHash, data, hashKeyBytes);
6011
  if (pHashItem == NULL) {
6012
    int32_t      size = sizeof(SUniqueItem) + pInfo->colBytes;
6013
    SUniqueItem* pItem = (SUniqueItem*)(pInfo->pItems + pInfo->numOfPoints * size);
6014
    pItem->timestamp = ts;
6015
    memcpy(pItem->data, data, pInfo->colBytes);
6016

6017
    taosHashPut(pInfo->pHash, data, hashKeyBytes, (char*)pItem, sizeof(SUniqueItem*));
6018
    pInfo->numOfPoints++;
6019
  } else if (pHashItem->timestamp > ts) {
6020
    pHashItem->timestamp = ts;
6021
  }
6022
}
6023
#endif
6024

6025
int32_t uniqueFunction(SqlFunctionCtx* pCtx) {
×
6026
#if 0
6027
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
6028
  SUniqueInfo*         pInfo = GET_ROWCELL_INTERBUF(pResInfo);
6029

6030
  SInputColumnInfoData* pInput = &pCtx->input;
6031
  TSKEY*                tsList = (int64_t*)pInput->pPTS->pData;
6032

6033
  SColumnInfoData* pInputCol = pInput->pData[0];
6034
  SColumnInfoData* pTsOutput = pCtx->pTsOutput;
6035
  SColumnInfoData* pOutput = (SColumnInfoData*)pCtx->pOutput;
6036

6037
  int32_t startOffset = pCtx->offset;
6038
  for (int32_t i = pInput->startRowIndex; i < pInput->numOfRows + pInput->startRowIndex; ++i) {
6039
    char* data = colDataGetData(pInputCol, i);
6040
    doUniqueAdd(pInfo, data, tsList[i], colDataIsNull_s(pInputCol, i));
6041

6042
    if (sizeof(SUniqueInfo) + pInfo->numOfPoints * (sizeof(SUniqueItem) + pInfo->colBytes) >= UNIQUE_MAX_RESULT_SIZE) {
6043
      taosHashCleanup(pInfo->pHash);
6044
      return 0;
6045
    }
6046
  }
6047

6048
  for (int32_t i = 0; i < pInfo->numOfPoints; ++i) {
6049
    SUniqueItem* pItem = (SUniqueItem*)(pInfo->pItems + i * (sizeof(SUniqueItem) + pInfo->colBytes));
6050
    if (pItem->isNull == true) {
6051
      colDataSetNULL(pOutput, i);
6052
    } else {
6053
      colDataSetVal(pOutput, i, pItem->data, false);
6054
    }
6055
    if (pTsOutput != NULL) {
6056
      colDataSetInt64(pTsOutput, i, &pItem->timestamp);
6057
    }
6058
  }
6059

6060
  return pInfo->numOfPoints;
6061
#endif
6062
  return 0;
×
6063
}
6064

6065
bool getModeFuncEnv(SFunctionNode* pFunc, SFuncExecEnv* pEnv) {
330,705✔
6066
  pEnv->calcMemSize = sizeof(SModeInfo);
330,705✔
6067
  return true;
330,705✔
6068
}
6069

6070
int32_t modeFunctionSetup(SqlFunctionCtx* pCtx, SResultRowEntryInfo* pResInfo) {
480,661✔
6071
  if (pResInfo->initialized) {
480,661✔
6072
    return TSDB_CODE_SUCCESS;
×
6073
  }
6074
  if (TSDB_CODE_SUCCESS != functionSetup(pCtx, pResInfo)) {
480,661✔
6075
    return TSDB_CODE_FUNC_SETUP_ERROR;
×
6076
  }
6077

6078
  SModeInfo* pInfo = GET_ROWCELL_INTERBUF(pResInfo);
480,661✔
6079
  pInfo->colType = pCtx->resDataInfo.type;
480,661✔
6080
  pInfo->colBytes = pCtx->resDataInfo.bytes;
480,661✔
6081
  if (pInfo->pHash != NULL) {
480,661✔
6082
    taosHashClear(pInfo->pHash);
×
6083
  } else {
6084
    pInfo->pHash = taosHashInit(64, taosGetDefaultHashFunction(TSDB_DATA_TYPE_BINARY), true, HASH_NO_LOCK);
480,661✔
6085
    if (NULL == pInfo->pHash) {
480,661✔
6086
      return terrno;
×
6087
    }
6088
  }
6089
  pInfo->nullTupleSaved = false;
480,661✔
6090
  pInfo->nullTuplePos.pageId = -1;
480,661✔
6091

6092
  pInfo->buf = taosMemoryMalloc(pInfo->colBytes);
480,661✔
6093
  if (NULL == pInfo->buf) {
480,661✔
6094
    taosHashCleanup(pInfo->pHash);
×
6095
    pInfo->pHash = NULL;
×
6096
    return terrno;
×
6097
  }
6098
  pCtx->needCleanup = true;
480,661✔
6099
  return TSDB_CODE_SUCCESS;
480,661✔
6100
}
6101

6102
static void modeFunctionCleanup(SModeInfo* pInfo) {
480,661✔
6103
  taosHashCleanup(pInfo->pHash);
480,661✔
6104
  pInfo->pHash = NULL;
480,661✔
6105
  taosMemoryFreeClear(pInfo->buf);
480,661✔
6106
}
480,661✔
6107

6108
void modeFunctionCleanupExt(SqlFunctionCtx* pCtx) {
×
6109
  if (pCtx == NULL || GET_RES_INFO(pCtx) == NULL || GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx)) == NULL) {
×
6110
    return;
×
6111
  }
6112
  modeFunctionCleanup(GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx)));
×
6113
}
6114

6115
static int32_t saveModeTupleData(SqlFunctionCtx* pCtx, char* data, SModeInfo* pInfo, STuplePos* pPos) {
32,852,401✔
6116
  if (IS_VAR_DATA_TYPE(pInfo->colType)) {
32,852,401✔
6117
    if (pInfo->colType == TSDB_DATA_TYPE_JSON) {
8,930,248✔
6118
      (void)memcpy(pInfo->buf, data, getJsonValueLen(data));
310,662✔
6119
    } else if (IS_STR_DATA_BLOB(pInfo->colType)) {
8,622,251✔
6120
      (void)memcpy(pInfo->buf, data, blobDataTLen(data));
×
6121
    } else {
6122
      (void)memcpy(pInfo->buf, data, varDataTLen(data));
8,622,251✔
6123
    }
6124
  } else {
6125
    (void)memcpy(pInfo->buf, data, pInfo->colBytes);
23,923,998✔
6126
  }
6127

6128
  return doSaveTupleData(&pCtx->saveHandle, pInfo->buf, pInfo->colBytes, NULL, pPos, pCtx->pStore);
32,856,706✔
6129
}
6130

6131
static int32_t doModeAdd(SModeInfo* pInfo, int32_t rowIndex, SqlFunctionCtx* pCtx, char* data) {
38,239,576✔
6132
  int32_t code = TSDB_CODE_SUCCESS;
38,239,576✔
6133
  int32_t hashKeyBytes;
6134
  if (IS_VAR_DATA_TYPE(pInfo->colType)) {
38,239,576✔
6135
    hashKeyBytes = calcStrBytesByType(pInfo->colType, data);
9,103,833✔
6136
  } else {
6137
    hashKeyBytes = pInfo->colBytes;
29,136,561✔
6138
  }
6139

6140
  SModeItem* pHashItem = (SModeItem*)taosHashGet(pInfo->pHash, data, hashKeyBytes);
38,241,829✔
6141
  if (pHashItem == NULL) {
38,238,137✔
6142
    int32_t   size = sizeof(SModeItem);
32,852,811✔
6143
    SModeItem item = {0};
32,852,811✔
6144

6145
    item.count += 1;
32,852,606✔
6146
    code = saveModeTupleData(pCtx, data, pInfo, &item.dataPos);
32,852,606✔
6147
    if (code != TSDB_CODE_SUCCESS) {
32,845,841✔
6148
      return code;
×
6149
    }
6150

6151
    if (pCtx->subsidiaries.num > 0) {
32,845,841✔
6152
      code = saveTupleData(pCtx, rowIndex, pCtx->pSrcBlock, &item.tuplePos);
61,530✔
6153
      if (code != TSDB_CODE_SUCCESS) {
61,530✔
6154
        return code;
×
6155
      }
6156
    }
6157

6158
    code = taosHashPut(pInfo->pHash, data, hashKeyBytes, &item, sizeof(SModeItem));
32,845,841✔
6159
    if (code != TSDB_CODE_SUCCESS) {
32,852,403✔
6160
      return code;
×
6161
    }
6162
  } else {
6163
    pHashItem->count += 1;
5,385,326✔
6164
    if (pCtx->subsidiaries.num > 0) {
5,385,326✔
6165
      code = updateTupleData(pCtx, rowIndex, pCtx->pSrcBlock, &pHashItem->tuplePos);
20,174✔
6166
      if (code != TSDB_CODE_SUCCESS) {
20,174✔
6167
        return code;
×
6168
      }
6169
    }
6170
  }
6171

6172
  return code;
38,236,917✔
6173
}
6174

6175
int32_t modeFunction(SqlFunctionCtx* pCtx) {
882,621✔
6176
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
882,621✔
6177
  SModeInfo*           pInfo = GET_ROWCELL_INTERBUF(pResInfo);
882,621✔
6178

6179
  SInputColumnInfoData* pInput = &pCtx->input;
882,621✔
6180

6181
  SColumnInfoData* pInputCol = pInput->pData[0];
882,499✔
6182
  SColumnInfoData* pOutput = (SColumnInfoData*)pCtx->pOutput;
882,621✔
6183

6184
  int32_t numOfElems = 0;
882,499✔
6185
  int32_t startOffset = pCtx->offset;
882,499✔
6186
  for (int32_t i = pInput->startRowIndex; i < pInput->numOfRows + pInput->startRowIndex; ++i) {
53,908,140✔
6187
    if (colDataIsNull_s(pInputCol, i)) {
106,061,228✔
6188
      continue;
14,796,247✔
6189
    }
6190
    numOfElems++;
38,239,170✔
6191

6192
    char*   data = colDataGetData(pInputCol, i);
38,239,170✔
6193
    int32_t code = doModeAdd(pInfo, i, pCtx, data);
38,241,831✔
6194
    if (code != TSDB_CODE_SUCCESS) {
38,237,122✔
6195
      modeFunctionCleanup(pInfo);
7,850✔
6196
      return code;
×
6197
    }
6198
  }
6199

6200
  if (numOfElems == 0 && pCtx->subsidiaries.num > 0 && !pInfo->nullTupleSaved) {
882,621✔
6201
    int32_t code = saveTupleData(pCtx, pInput->startRowIndex, pCtx->pSrcBlock, &pInfo->nullTuplePos);
5,180✔
6202
    if (code != TSDB_CODE_SUCCESS) {
5,180✔
6203
      modeFunctionCleanup(pInfo);
×
6204
      return code;
×
6205
    }
6206
    pInfo->nullTupleSaved = true;
5,180✔
6207
  }
6208

6209
  SET_VAL(pResInfo, numOfElems, 1);
882,621✔
6210

6211
  return TSDB_CODE_SUCCESS;
882,621✔
6212
}
6213

6214
int32_t modeFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
480,661✔
6215
  int32_t              code = TSDB_CODE_SUCCESS;
480,661✔
6216
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
480,661✔
6217
  SModeInfo*           pInfo = GET_ROWCELL_INTERBUF(pResInfo);
480,661✔
6218
  int32_t              slotId = pCtx->pExpr->base.resSchema.slotId;
480,456✔
6219
  SColumnInfoData*     pCol = taosArrayGet(pBlock->pDataBlock, slotId);
480,661✔
6220
  int32_t              currentRow = pBlock->info.rows;
480,661✔
6221
  if (NULL == pCol) {
480,661✔
6222
    modeFunctionCleanup(pInfo);
×
6223
    return TSDB_CODE_OUT_OF_RANGE;
×
6224
  }
6225

6226
  STuplePos resDataPos, resTuplePos;
480,661✔
6227
  int32_t   maxCount = 0;
480,661✔
6228

6229
  void* pIter = taosHashIterate(pInfo->pHash, NULL);
480,661✔
6230
  while (pIter != NULL) {
33,331,028✔
6231
    SModeItem* pItem = (SModeItem*)pIter;
32,850,367✔
6232
    if (pItem->count >= maxCount) {
32,850,367✔
6233
      maxCount = pItem->count;
25,688,172✔
6234
      resDataPos = pItem->dataPos;
25,688,172✔
6235
      resTuplePos = pItem->tuplePos;
25,687,967✔
6236
    }
6237

6238
    pIter = taosHashIterate(pInfo->pHash, pIter);
32,852,212✔
6239
  }
6240

6241
  if (maxCount != 0) {
480,661✔
6242
    char* pData = NULL;
388,467✔
6243
    code = loadTupleData(pCtx, &resDataPos, &pData);
388,467✔
6244
    if (pData == NULL || TSDB_CODE_SUCCESS != code) {
388,467✔
6245
      code = terrno = TSDB_CODE_NOT_FOUND;
×
6246
      qError("Load tuple data failed since %s, groupId:%" PRIu64 ", ts:%" PRId64, terrstr(),
×
6247
             resDataPos.streamTupleKey.groupId, resDataPos.streamTupleKey.ts);
6248
      modeFunctionCleanup(pInfo);
×
6249
      return code;
×
6250
    }
6251

6252
    code = colDataSetVal(pCol, currentRow, pData, false);
388,467✔
6253
    if (TSDB_CODE_SUCCESS != code) {
388,467✔
6254
      modeFunctionCleanup(pInfo);
×
6255
      return code;
×
6256
    }
6257
    code = setSelectivityValue(pCtx, pBlock, &resTuplePos, currentRow);
388,467✔
6258
  } else {
6259
    colDataSetNULL(pCol, currentRow);
92,194✔
6260
    code = setSelectivityValue(pCtx, pBlock, &pInfo->nullTuplePos, currentRow);
92,194✔
6261
  }
6262

6263
  modeFunctionCleanup(pInfo);
480,661✔
6264

6265
  return code;
480,661✔
6266
}
6267

6268
bool getTwaFuncEnv(struct SFunctionNode* pFunc, SFuncExecEnv* pEnv) {
234,672✔
6269
  pEnv->calcMemSize = sizeof(STwaInfo);
234,672✔
6270
  return true;
234,672✔
6271
}
6272

6273
int32_t twaFunctionSetup(SqlFunctionCtx* pCtx, SResultRowEntryInfo* pResultInfo) {
7,042,071✔
6274
  if (pResultInfo->initialized) {
7,042,071✔
6275
    return TSDB_CODE_SUCCESS;
×
6276
  }
6277
  if (TSDB_CODE_SUCCESS != functionSetup(pCtx, pResultInfo)) {
7,044,586✔
6278
    return TSDB_CODE_FUNC_SETUP_ERROR;
×
6279
  }
6280

6281
  STwaInfo* pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
7,044,586✔
6282
  pInfo->numOfElems = 0;
7,044,586✔
6283
  pInfo->p.key = INT64_MIN;
7,044,586✔
6284
  pInfo->win = TSWINDOW_INITIALIZER;
7,044,586✔
6285
  return TSDB_CODE_SUCCESS;
7,044,586✔
6286
}
6287

6288
static double twa_get_area(SPoint1 s, SPoint1 e) {
143,729,835✔
6289
  if (e.key == INT64_MAX || s.key == INT64_MIN) {
143,729,835✔
6290
    return 0;
48,629✔
6291
  }
6292

6293
  if ((s.val >= 0 && e.val >= 0) || (s.val <= 0 && e.val <= 0)) {
143,681,206✔
6294
    return (s.val + e.val) * (e.key - s.key) / 2;
142,003,008✔
6295
  }
6296

6297
  double x = (s.key * e.val - e.key * s.val) / (e.val - s.val);
1,715,465✔
6298
  double val = (s.val * (x - s.key) + e.val * (e.key - x)) / 2;
1,715,465✔
6299
  return val;
1,715,465✔
6300
}
6301

6302
int32_t twaFunction(SqlFunctionCtx* pCtx) {
7,066,591✔
6303
  int32_t               code = TSDB_CODE_SUCCESS;
7,066,591✔
6304
  SInputColumnInfoData* pInput = &pCtx->input;
7,066,591✔
6305
  SColumnInfoData*      pInputCol = pInput->pData[0];
7,066,591✔
6306

6307
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
7,066,591✔
6308
  STwaInfo*            pInfo = GET_ROWCELL_INTERBUF(pResInfo);
7,066,591✔
6309
  SPoint1*             last = &pInfo->p;
7,066,591✔
6310

6311
  if (IS_NULL_TYPE(pInputCol->info.type)) {
7,066,591✔
6312
    pInfo->numOfElems = 0;
×
6313
    goto _twa_over;
×
6314
  }
6315

6316
  funcInputUpdate(pCtx);
7,066,088✔
6317
  SFuncInputRow row = {0};
7,066,591✔
6318
  bool          result = false;
7,066,591✔
6319
  if (pCtx->start.key != INT64_MIN && last->key == INT64_MIN) {
7,066,591✔
6320
    while (1) {
6321
      code = funcInputGetNextRow(pCtx, &row, &result);
5,648,668✔
6322
      if (TSDB_CODE_SUCCESS != code) {
5,648,668✔
6323
        return code;
×
6324
      }
6325
      if (!result) {
5,648,668✔
6326
        break;
968✔
6327
      }
6328
      if (row.isDataNull) {
5,647,700✔
6329
        continue;
968✔
6330
      }
6331

6332
      last->key = row.ts;
5,646,732✔
6333

6334
      GET_TYPED_DATA(last->val, double, pInputCol->info.type, row.pData, typeGetTypeModFromColInfo(&pInputCol->info));
5,646,732✔
6335

6336
      pInfo->dOutput += twa_get_area(pCtx->start, *last);
5,646,732✔
6337
      pInfo->win.skey = pCtx->start.key;
5,646,732✔
6338
      pInfo->numOfElems++;
5,646,732✔
6339
      break;
5,646,732✔
6340
    }
6341
  } else if (pInfo->p.key == INT64_MIN) {
1,418,891✔
6342
    while (1) {
6343
      code = funcInputGetNextRow(pCtx, &row, &result);
4,196,948✔
6344
      if (TSDB_CODE_SUCCESS != code) {
4,197,451✔
6345
        return code;
×
6346
      }
6347
      if (!result) {
4,197,451✔
6348
        break;
326,317✔
6349
      }
6350
      if (row.isDataNull) {
3,871,134✔
6351
        continue;
2,797,695✔
6352
      }
6353

6354
      last->key = row.ts;
1,073,439✔
6355

6356
      GET_TYPED_DATA(last->val, double, pInputCol->info.type, row.pData, typeGetTypeModFromColInfo(&pInputCol->info));
1,073,439✔
6357

6358
      pInfo->win.skey = last->key;
1,073,439✔
6359
      pInfo->numOfElems++;
1,073,439✔
6360
      break;
1,073,439✔
6361
    }
6362
  }
6363

6364
  SPoint1 st = {0};
7,066,591✔
6365

6366
  // calculate the value of
6367
  while (1) {
6368
    code = funcInputGetNextRow(pCtx, &row, &result);
139,564,087✔
6369
    if (TSDB_CODE_SUCCESS != code) {
139,570,757✔
6370
      return code;
×
6371
    }
6372
    if (!result) {
139,570,757✔
6373
      break;
7,066,591✔
6374
    }
6375
    if (row.isDataNull) {
132,504,166✔
6376
      continue;
63,378✔
6377
    }
6378
    pInfo->numOfElems++;
132,440,788✔
6379
    switch (pInputCol->info.type) {
132,442,042✔
6380
      case TSDB_DATA_TYPE_TINYINT: {
14,259,215✔
6381
        INIT_INTP_POINT(st, row.ts, *(int8_t*)row.pData);
14,259,215✔
6382
        break;
14,259,215✔
6383
      }
6384
      case TSDB_DATA_TYPE_SMALLINT: {
14,141,237✔
6385
        INIT_INTP_POINT(st, row.ts, *(int16_t*)row.pData);
14,141,237✔
6386
        break;
14,141,237✔
6387
      }
6388
      case TSDB_DATA_TYPE_INT: {
22,515,686✔
6389
        INIT_INTP_POINT(st, row.ts, *(int32_t*)row.pData);
22,515,686✔
6390
        break;
22,515,686✔
6391
      }
6392
      case TSDB_DATA_TYPE_BIGINT: {
15,124,673✔
6393
        INIT_INTP_POINT(st, row.ts, *(int64_t*)row.pData);
15,124,673✔
6394
        break;
15,124,673✔
6395
      }
6396
      case TSDB_DATA_TYPE_FLOAT: {
12,533,886✔
6397
        INIT_INTP_POINT(st, row.ts, *(float_t*)row.pData);
12,533,886✔
6398
        break;
12,533,886✔
6399
      }
6400
      case TSDB_DATA_TYPE_DOUBLE: {
14,189,211✔
6401
        INIT_INTP_POINT(st, row.ts, *(double*)row.pData);
14,189,211✔
6402
        break;
14,189,714✔
6403
      }
6404
      case TSDB_DATA_TYPE_UTINYINT: {
10,158,176✔
6405
        INIT_INTP_POINT(st, row.ts, *(uint8_t*)row.pData);
10,158,176✔
6406
        break;
10,158,176✔
6407
      }
6408
      case TSDB_DATA_TYPE_USMALLINT: {
10,147,613✔
6409
        INIT_INTP_POINT(st, row.ts, *(uint16_t*)row.pData);
10,147,613✔
6410
        break;
10,146,104✔
6411
      }
6412
      case TSDB_DATA_TYPE_UINT: {
10,208,476✔
6413
        INIT_INTP_POINT(st, row.ts, *(uint32_t*)row.pData);
10,208,476✔
6414
        break;
10,208,476✔
6415
      }
6416
      case TSDB_DATA_TYPE_UBIGINT: {
9,162,236✔
6417
        INIT_INTP_POINT(st, row.ts, *(uint64_t*)row.pData);
9,162,236✔
6418
        break;
9,161,733✔
6419
      }
6420
      default: {
×
6421
        return TSDB_CODE_FUNC_FUNTION_PARA_TYPE;
×
6422
      }
6423
    }
6424
    if (pInfo->p.key == st.key) {
132,438,900✔
6425
      return TSDB_CODE_FUNC_DUP_TIMESTAMP;
×
6426
    }
6427

6428
    pInfo->dOutput += twa_get_area(pInfo->p, st);
132,436,888✔
6429
    pInfo->p = st;
132,430,473✔
6430
  }
6431

6432
  // the last interpolated time window value
6433
  if (pCtx->end.key != INT64_MIN) {
7,066,591✔
6434
    pInfo->dOutput += twa_get_area(pInfo->p, pCtx->end);
5,650,239✔
6435
    pInfo->p = pCtx->end;
5,650,239✔
6436
    pInfo->numOfElems += 1;
5,650,239✔
6437
  }
6438

6439
  pInfo->win.ekey = pInfo->p.key;
7,066,591✔
6440

6441
_twa_over:
7,066,591✔
6442
  SET_VAL(pResInfo, 1, 1);
7,066,591✔
6443
  return TSDB_CODE_SUCCESS;
7,066,591✔
6444
}
6445

6446
/*
6447
 * To copy the input to interResBuf to avoid the input buffer space be over writen
6448
 * by next input data. The TWA function only applies to each table, so no merge procedure
6449
 * is required, we simply copy to the resut ot interResBuffer.
6450
 */
6451
// void twa_function_copy(SQLFunctionCtx *pCtx) {
6452
//   SResultRowEntryInfo *pResInfo = GET_RES_INFO(pCtx);
6453
//
6454
//   memcpy(GET_ROWCELL_INTERBUF(pResInfo), pCtx->pInput, (size_t)pCtx->inputBytes);
6455
//   pResInfo->hasResult = ((STwaInfo *)pCtx->pInput)->hasResult;
6456
// }
6457

6458
int32_t twaFinalize(struct SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
7,044,586✔
6459
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
7,044,586✔
6460

6461
  STwaInfo* pInfo = (STwaInfo*)GET_ROWCELL_INTERBUF(pResInfo);
7,044,586✔
6462
  if (pInfo->numOfElems == 0) {
7,044,586✔
6463
    pResInfo->numOfRes = 0;
323,447✔
6464
  } else {
6465
    if (pInfo->win.ekey == pInfo->win.skey) {
6,721,139✔
6466
      pInfo->dTwaRes = pInfo->p.val;
200,165✔
6467
    } else if (pInfo->win.ekey == INT64_MAX || pInfo->win.skey == INT64_MIN) {  // no data in timewindow
6,520,974✔
6468
      pInfo->dTwaRes = 0;
968✔
6469
    } else {
6470
      pInfo->dTwaRes = pInfo->dOutput / (pInfo->win.ekey - pInfo->win.skey);
6,520,006✔
6471
    }
6472

6473
    pResInfo->numOfRes = 1;
6,721,139✔
6474
  }
6475

6476
  return functionFinalize(pCtx, pBlock);
7,044,586✔
6477
}
6478

6479
int32_t blockDistSetup(SqlFunctionCtx* pCtx, SResultRowEntryInfo* pResultInfo) {
4,535✔
6480
  if (pResultInfo->initialized) {
4,535✔
6481
    return TSDB_CODE_SUCCESS;
×
6482
  }
6483
  if (TSDB_CODE_SUCCESS != functionSetup(pCtx, pResultInfo)) {
4,535✔
6484
    return TSDB_CODE_FUNC_SETUP_ERROR;
×
6485
  }
6486

6487
  STableBlockDistInfo* pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
4,535✔
6488
  pInfo->minRows = INT32_MAX;
4,535✔
6489
  return TSDB_CODE_SUCCESS;
4,535✔
6490
}
6491

6492
int32_t blockDistFunction(SqlFunctionCtx* pCtx) {
8,407✔
6493
  const int32_t BLOCK_DIST_RESULT_ROWS = 25;
8,407✔
6494

6495
  SInputColumnInfoData* pInput = &pCtx->input;
8,407✔
6496
  SColumnInfoData*      pInputCol = pInput->pData[0];
8,407✔
6497
  SResultRowEntryInfo*  pResInfo = GET_RES_INFO(pCtx);
8,407✔
6498
  STableBlockDistInfo*  pDistInfo = GET_ROWCELL_INTERBUF(pResInfo);
8,407✔
6499

6500
  STableBlockDistInfo p1 = {0};
8,407✔
6501
  if (tDeserializeBlockDistInfo(varDataVal(pInputCol->pData), varDataLen(pInputCol->pData), &p1) < 0) {
8,407✔
6502
    qError("failed to deserialize block dist info");
×
6503
    return TSDB_CODE_FAILED;
×
6504
  }
6505

6506
  pDistInfo->numOfBlocks += p1.numOfBlocks;
8,407✔
6507
  pDistInfo->numOfTables += p1.numOfTables;
8,407✔
6508
  pDistInfo->numOfInmemRows += p1.numOfInmemRows;
8,407✔
6509
  pDistInfo->numOfSttRows += p1.numOfSttRows;
8,407✔
6510
  pDistInfo->totalSize += p1.totalSize;
8,407✔
6511
  pDistInfo->totalRows += p1.totalRows;
8,407✔
6512
  pDistInfo->numOfFiles += p1.numOfFiles;
8,407✔
6513

6514
  pDistInfo->defMinRows = p1.defMinRows;
8,407✔
6515
  pDistInfo->defMaxRows = p1.defMaxRows;
8,407✔
6516
  pDistInfo->rowSize = p1.rowSize;
8,407✔
6517

6518
  if (pDistInfo->minRows > p1.minRows) {
8,407✔
6519
    pDistInfo->minRows = p1.minRows;
1,334✔
6520
  }
6521
  if (pDistInfo->maxRows < p1.maxRows) {
8,407✔
6522
    pDistInfo->maxRows = p1.maxRows;
1,334✔
6523
  }
6524
  pDistInfo->numOfVgroups += (p1.numOfTables != 0 ? 1 : 0);
8,407✔
6525
  for (int32_t i = 0; i < tListLen(pDistInfo->blockRowsHisto); ++i) {
176,547✔
6526
    pDistInfo->blockRowsHisto[i] += p1.blockRowsHisto[i];
168,140✔
6527
  }
6528

6529
  pResInfo->numOfRes = BLOCK_DIST_RESULT_ROWS;  // default output rows
8,407✔
6530
  return TSDB_CODE_SUCCESS;
8,407✔
6531
}
6532

6533
int32_t tSerializeBlockDistInfo(void* buf, int32_t bufLen, const STableBlockDistInfo* pInfo) {
16,814✔
6534
  SEncoder encoder = {0};
16,814✔
6535
  int32_t  code = 0;
16,814✔
6536
  int32_t  lino;
6537
  int32_t  tlen;
6538
  tEncoderInit(&encoder, buf, bufLen);
16,814✔
6539

6540
  TAOS_CHECK_EXIT(tStartEncode(&encoder));
16,814✔
6541
  TAOS_CHECK_EXIT(tEncodeU32(&encoder, pInfo->rowSize));
33,628✔
6542

6543
  TAOS_CHECK_EXIT(tEncodeU16(&encoder, pInfo->numOfFiles));
33,628✔
6544
  TAOS_CHECK_EXIT(tEncodeU32(&encoder, pInfo->numOfBlocks));
33,628✔
6545
  TAOS_CHECK_EXIT(tEncodeU32(&encoder, pInfo->numOfTables));
33,628✔
6546

6547
  TAOS_CHECK_EXIT(tEncodeU64(&encoder, pInfo->totalSize));
33,628✔
6548
  TAOS_CHECK_EXIT(tEncodeU64(&encoder, pInfo->totalRows));
33,628✔
6549
  TAOS_CHECK_EXIT(tEncodeI32(&encoder, pInfo->maxRows));
33,628✔
6550
  TAOS_CHECK_EXIT(tEncodeI32(&encoder, pInfo->minRows));
33,628✔
6551
  TAOS_CHECK_EXIT(tEncodeI32(&encoder, pInfo->defMaxRows));
33,628✔
6552
  TAOS_CHECK_EXIT(tEncodeI32(&encoder, pInfo->defMinRows));
33,628✔
6553
  TAOS_CHECK_EXIT(tEncodeU32(&encoder, pInfo->numOfInmemRows));
33,628✔
6554
  TAOS_CHECK_EXIT(tEncodeU32(&encoder, pInfo->numOfSttRows));
33,628✔
6555
  TAOS_CHECK_EXIT(tEncodeU32(&encoder, pInfo->numOfVgroups));
33,628✔
6556

6557
  for (int32_t i = 0; i < tListLen(pInfo->blockRowsHisto); ++i) {
353,094✔
6558
    TAOS_CHECK_EXIT(tEncodeI32(&encoder, pInfo->blockRowsHisto[i]));
672,560✔
6559
  }
6560

6561
  tEndEncode(&encoder);
16,814✔
6562

6563
_exit:
16,814✔
6564
  if (code) {
16,814✔
6565
    tlen = code;
×
6566
  } else {
6567
    tlen = encoder.pos;
16,814✔
6568
  }
6569
  tEncoderClear(&encoder);
16,814✔
6570
  return tlen;
16,814✔
6571
}
6572

6573
int32_t tDeserializeBlockDistInfo(void* buf, int32_t bufLen, STableBlockDistInfo* pInfo) {
8,407✔
6574
  SDecoder decoder = {0};
8,407✔
6575
  int32_t  code = 0;
8,407✔
6576
  int32_t  lino;
6577
  tDecoderInit(&decoder, buf, bufLen);
8,407✔
6578

6579
  TAOS_CHECK_EXIT(tStartDecode(&decoder));
8,407✔
6580
  TAOS_CHECK_EXIT(tDecodeU32(&decoder, &pInfo->rowSize));
16,814✔
6581

6582
  TAOS_CHECK_EXIT(tDecodeU16(&decoder, &pInfo->numOfFiles));
16,814✔
6583
  TAOS_CHECK_EXIT(tDecodeU32(&decoder, &pInfo->numOfBlocks));
16,814✔
6584
  TAOS_CHECK_EXIT(tDecodeU32(&decoder, &pInfo->numOfTables));
16,814✔
6585

6586
  TAOS_CHECK_EXIT(tDecodeU64(&decoder, &pInfo->totalSize));
16,814✔
6587
  TAOS_CHECK_EXIT(tDecodeU64(&decoder, &pInfo->totalRows));
16,814✔
6588
  TAOS_CHECK_EXIT(tDecodeI32(&decoder, &pInfo->maxRows));
16,814✔
6589
  TAOS_CHECK_EXIT(tDecodeI32(&decoder, &pInfo->minRows));
16,814✔
6590
  TAOS_CHECK_EXIT(tDecodeI32(&decoder, &pInfo->defMaxRows));
16,814✔
6591
  TAOS_CHECK_EXIT(tDecodeI32(&decoder, &pInfo->defMinRows));
16,814✔
6592
  TAOS_CHECK_EXIT(tDecodeU32(&decoder, &pInfo->numOfInmemRows));
16,814✔
6593
  TAOS_CHECK_EXIT(tDecodeU32(&decoder, &pInfo->numOfSttRows));
16,814✔
6594
  TAOS_CHECK_EXIT(tDecodeU32(&decoder, &pInfo->numOfVgroups));
16,814✔
6595

6596
  for (int32_t i = 0; i < tListLen(pInfo->blockRowsHisto); ++i) {
176,547✔
6597
    TAOS_CHECK_EXIT(tDecodeI32(&decoder, &pInfo->blockRowsHisto[i]));
336,280✔
6598
  }
6599

6600
_exit:
8,407✔
6601
  tDecoderClear(&decoder);
8,407✔
6602
  return code;
8,407✔
6603
}
6604

6605
int32_t blockDistFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
4,535✔
6606
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
4,535✔
6607
  STableBlockDistInfo* pData = GET_ROWCELL_INTERBUF(pResInfo);
4,535✔
6608

6609
  SColumnInfoData* pColInfo = taosArrayGet(pBlock->pDataBlock, 0);
4,535✔
6610
  if (NULL == pColInfo) {
4,535✔
6611
    return TSDB_CODE_OUT_OF_RANGE;
×
6612
  }
6613

6614
  if (pData->totalRows == 0) {
4,535✔
6615
    pData->minRows = 0;
3,201✔
6616
  }
6617

6618
  int32_t row = 0;
4,535✔
6619
  char    st[256] = {0};
4,535✔
6620
  double  averageSize = 0;
4,535✔
6621
  if (pData->numOfBlocks != 0) {
4,535✔
6622
    averageSize = ((double)pData->totalSize) / pData->numOfBlocks;
1,334✔
6623
  }
6624
  uint64_t totalRawSize = pData->totalRows * pData->rowSize;
4,535✔
6625
  double   compRatio = 0;
4,535✔
6626
  if (totalRawSize != 0) {
4,535✔
6627
    compRatio = pData->totalSize * 100 / (double)totalRawSize;
1,334✔
6628
  }
6629

6630
  int32_t len = tsnprintf(varDataVal(st), sizeof(st) - VARSTR_HEADER_SIZE,
4,535✔
6631
                          "Total_Blocks=[%d] Total_Size=[%.2f KiB] Average_size=[%.2f KiB] Compression_Ratio=[%.2f %c]",
6632
                          pData->numOfBlocks, pData->totalSize / 1024.0, averageSize / 1024.0, compRatio, '%');
4,535✔
6633

6634
  varDataSetLen(st, len);
4,535✔
6635
  int32_t code = colDataSetVal(pColInfo, row++, st, false);
4,535✔
6636
  if (TSDB_CODE_SUCCESS != code) {
4,535✔
6637
    return code;
×
6638
  }
6639

6640
  int64_t avgRows = 0;
4,535✔
6641
  if (pData->numOfBlocks > 0) {
4,535✔
6642
    avgRows = pData->totalRows / pData->numOfBlocks;
1,334✔
6643
  }
6644

6645
  len = tsnprintf(varDataVal(st), sizeof(st) - VARSTR_HEADER_SIZE,
4,535✔
6646
                  "Block_Rows=[%" PRId64 "] MinRows=[%d] MaxRows=[%d] AvgRows=[%" PRId64 "]", pData->totalRows,
6647
                  pData->minRows, pData->maxRows, avgRows);
6648
  varDataSetLen(st, len);
4,535✔
6649
  code = colDataSetVal(pColInfo, row++, st, false);
4,535✔
6650
  if (TSDB_CODE_SUCCESS != code) {
4,535✔
6651
    return code;
×
6652
  }
6653

6654
  len = tsnprintf(varDataVal(st), sizeof(st) - VARSTR_HEADER_SIZE, "Inmem_Rows=[%u] Stt_Rows=[%u] ",
4,535✔
6655
                  pData->numOfInmemRows, pData->numOfSttRows);
6656
  varDataSetLen(st, len);
4,535✔
6657
  code = colDataSetVal(pColInfo, row++, st, false);
4,535✔
6658
  if (TSDB_CODE_SUCCESS != code) {
4,535✔
6659
    return code;
×
6660
  }
6661

6662
  len = tsnprintf(varDataVal(st), sizeof(st) - VARSTR_HEADER_SIZE,
9,070✔
6663
                  "Total_Tables=[%d] Total_Filesets=[%d] Total_Vgroups=[%d]", pData->numOfTables, pData->numOfFiles,
4,535✔
6664
                  pData->numOfVgroups);
6665

6666
  varDataSetLen(st, len);
4,535✔
6667
  code = colDataSetVal(pColInfo, row++, st, false);
4,535✔
6668
  if (TSDB_CODE_SUCCESS != code) {
4,535✔
6669
    return code;
×
6670
  }
6671

6672
  len = tsnprintf(varDataVal(st), sizeof(st) - VARSTR_HEADER_SIZE,
4,535✔
6673
                  "--------------------------------------------------------------------------------");
6674
  varDataSetLen(st, len);
4,535✔
6675
  code = colDataSetVal(pColInfo, row++, st, false);
4,535✔
6676
  if (TSDB_CODE_SUCCESS != code) {
4,535✔
6677
    return code;
×
6678
  }
6679

6680
  int32_t maxVal = 0;
4,535✔
6681
  int32_t minVal = INT32_MAX;
4,535✔
6682
  for (int32_t i = 0; i < tListLen(pData->blockRowsHisto); ++i) {
95,235✔
6683
    if (maxVal < pData->blockRowsHisto[i]) {
90,700✔
6684
      maxVal = pData->blockRowsHisto[i];
1,928✔
6685
    }
6686

6687
    if (minVal > pData->blockRowsHisto[i]) {
90,700✔
6688
      minVal = pData->blockRowsHisto[i];
5,275✔
6689
    }
6690
  }
6691

6692
  // maximum number of step is 80
6693
  double factor = pData->numOfBlocks / 80.0;
4,535✔
6694

6695
  int32_t numOfBuckets = sizeof(pData->blockRowsHisto) / sizeof(pData->blockRowsHisto[0]);
4,535✔
6696
  int32_t bucketRange = ceil(((double)(pData->defMaxRows - pData->defMinRows)) / numOfBuckets);
4,535✔
6697

6698
  for (int32_t i = 0; i < tListLen(pData->blockRowsHisto); ++i) {
95,235✔
6699
    len =
90,700✔
6700
        tsnprintf(varDataVal(st), sizeof(st) - VARSTR_HEADER_SIZE, "%04d |", pData->defMinRows + bucketRange * (i + 1));
90,700✔
6701

6702
    int32_t num = 0;
90,700✔
6703
    if (pData->blockRowsHisto[i] > 0) {
90,700✔
6704
      num = (pData->blockRowsHisto[i]) / factor;
3,116✔
6705
    }
6706

6707
    for (int32_t j = 0; j < num; ++j) {
196,826✔
6708
      int32_t x = tsnprintf(varDataVal(st) + len, sizeof(st) - VARSTR_HEADER_SIZE - len, "%c", '|');
106,126✔
6709
      len += x;
106,126✔
6710
    }
6711

6712
    if (pData->blockRowsHisto[i] > 0) {
90,700✔
6713
      double v = pData->blockRowsHisto[i] * 100.0 / pData->numOfBlocks;
3,116✔
6714
      len += tsnprintf(varDataVal(st) + len, sizeof(st) - VARSTR_HEADER_SIZE - len, "  %d (%.2f%c)",
3,116✔
6715
                       pData->blockRowsHisto[i], v, '%');
6716
    }
6717

6718
    varDataSetLen(st, len);
90,700✔
6719
    code = colDataSetVal(pColInfo, row++, st, false);
90,700✔
6720
    if (TSDB_CODE_SUCCESS != code) {
90,700✔
6721
      return code;
×
6722
    }
6723
  }
6724

6725
  return TSDB_CODE_SUCCESS;
4,535✔
6726
}
6727
int32_t blockDBUsageSetup(SqlFunctionCtx* pCtx, SResultRowEntryInfo* pResultInfo) {
726✔
6728
  if (pResultInfo->initialized) {
726✔
6729
    return TSDB_CODE_SUCCESS;
×
6730
  }
6731
  if (TSDB_CODE_SUCCESS != functionSetup(pCtx, pResultInfo)) {
726✔
6732
    return TSDB_CODE_FUNC_SETUP_ERROR;
×
6733
  }
6734

6735
  SDBBlockUsageInfo* pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
726✔
6736
  return TSDB_CODE_SUCCESS;
726✔
6737
}
6738
int32_t blockDBUsageFunction(SqlFunctionCtx* pCtx) {
1,452✔
6739
  const int32_t BLOCK_DISK_USAGE_RESULT_ROWS = 2;
1,452✔
6740

6741
  SInputColumnInfoData* pInput = &pCtx->input;
1,452✔
6742
  SColumnInfoData*      pInputCol = pInput->pData[0];
1,452✔
6743
  SResultRowEntryInfo*  pResInfo = GET_RES_INFO(pCtx);
1,452✔
6744
  SDBBlockUsageInfo*    pDistInfo = GET_ROWCELL_INTERBUF(pResInfo);
1,452✔
6745

6746
  SDBBlockUsageInfo p1 = {0};
1,452✔
6747
  if (tDeserializeBlockDbUsage(varDataVal(pInputCol->pData), varDataLen(pInputCol->pData), &p1) < 0) {
1,452✔
6748
    qError("failed to deserialize block dist info");
×
6749
    return TSDB_CODE_FAILED;
×
6750
  }
6751

6752
  pDistInfo->dataInDiskSize += p1.dataInDiskSize;
1,452✔
6753
  pDistInfo->walInDiskSize += p1.walInDiskSize;
1,452✔
6754
  pDistInfo->rawDataSize += p1.rawDataSize;
1,452✔
6755
  pResInfo->numOfRes = BLOCK_DISK_USAGE_RESULT_ROWS;  // default output rows
1,452✔
6756
  return TSDB_CODE_SUCCESS;
1,452✔
6757
}
6758

6759
int32_t tSerializeBlockDbUsage(void* buf, int32_t bufLen, const SDBBlockUsageInfo* pInfo) {
2,904✔
6760
  SEncoder encoder = {0};
2,904✔
6761
  int32_t  code = 0;
2,904✔
6762
  int32_t  lino;
6763
  int32_t  tlen;
6764
  tEncoderInit(&encoder, buf, bufLen);
2,904✔
6765

6766
  TAOS_CHECK_EXIT(tStartEncode(&encoder));
2,904✔
6767

6768
  TAOS_CHECK_EXIT(tEncodeU64(&encoder, pInfo->dataInDiskSize));
5,808✔
6769
  TAOS_CHECK_EXIT(tEncodeU64(&encoder, pInfo->walInDiskSize));
5,808✔
6770
  TAOS_CHECK_EXIT(tEncodeU64(&encoder, pInfo->rawDataSize));
5,808✔
6771

6772
  tEndEncode(&encoder);
2,904✔
6773

6774
_exit:
2,904✔
6775
  if (code) {
2,904✔
6776
    tlen = code;
×
6777
  } else {
6778
    tlen = encoder.pos;
2,904✔
6779
  }
6780
  tEncoderClear(&encoder);
2,904✔
6781
  return tlen;
2,904✔
6782
}
6783
int32_t tDeserializeBlockDbUsage(void* buf, int32_t bufLen, SDBBlockUsageInfo* pInfo) {
1,452✔
6784
  SDecoder decoder = {0};
1,452✔
6785
  int32_t  code = 0;
1,452✔
6786
  int32_t  lino;
6787
  tDecoderInit(&decoder, buf, bufLen);
1,452✔
6788

6789
  TAOS_CHECK_EXIT(tStartDecode(&decoder));
1,452✔
6790
  TAOS_CHECK_EXIT(tDecodeU64(&decoder, &pInfo->dataInDiskSize));
2,904✔
6791
  TAOS_CHECK_EXIT(tDecodeU64(&decoder, &pInfo->walInDiskSize));
2,904✔
6792
  TAOS_CHECK_EXIT(tDecodeU64(&decoder, &pInfo->rawDataSize));
2,904✔
6793

6794
_exit:
1,452✔
6795
  tDecoderClear(&decoder);
1,452✔
6796
  return code;
1,452✔
6797
}
6798
int32_t blockDBUsageFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
726✔
6799
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
726✔
6800
  SDBBlockUsageInfo*   pData = GET_ROWCELL_INTERBUF(pResInfo);
726✔
6801

6802
  SColumnInfoData* pColInfo = taosArrayGet(pBlock->pDataBlock, 0);
726✔
6803
  if (NULL == pColInfo) {
726✔
6804
    return TSDB_CODE_OUT_OF_RANGE;
×
6805
  }
6806
  int32_t len = 0;
726✔
6807
  int32_t row = 0;
726✔
6808
  char    st[256] = {0};
726✔
6809

6810
  uint64_t totalDiskSize = pData->dataInDiskSize;
726✔
6811
  uint64_t rawDataSize = pData->rawDataSize;
726✔
6812
  double   compressRatio = 0;
726✔
6813
  if (rawDataSize != 0) {
726✔
6814
    compressRatio = totalDiskSize * 100 / (double)rawDataSize;
364✔
6815
    len = tsnprintf(varDataVal(st), sizeof(st) - VARSTR_HEADER_SIZE, "Compress_ratio=[%.2f%]", compressRatio);
364✔
6816
  } else {
6817
    len = tsnprintf(varDataVal(st), sizeof(st) - VARSTR_HEADER_SIZE, "Compress_ratio=[NULL]");
362✔
6818
  }
6819

6820
  varDataSetLen(st, len);
726✔
6821
  int32_t code = colDataSetVal(pColInfo, row++, st, false);
726✔
6822
  if (TSDB_CODE_SUCCESS != code) {
726✔
6823
    return code;
×
6824
  }
6825

6826
  len =
726✔
6827
      tsnprintf(varDataVal(st), sizeof(st) - VARSTR_HEADER_SIZE, "Disk_occupied=[%" PRId64 "k]", pData->dataInDiskSize);
726✔
6828
  varDataSetLen(st, len);
726✔
6829
  code = colDataSetVal(pColInfo, row++, st, false);
726✔
6830
  if (TSDB_CODE_SUCCESS != code) {
726✔
6831
    return code;
×
6832
  }
6833
  return code;
726✔
6834
}
6835

6836
bool getDerivativeFuncEnv(struct SFunctionNode* pFunc, SFuncExecEnv* pEnv) {
81,041✔
6837
  pEnv->calcMemSize = sizeof(SDerivInfo);
81,041✔
6838
  return true;
81,041✔
6839
}
6840

6841
int32_t derivativeFuncSetup(SqlFunctionCtx* pCtx, SResultRowEntryInfo* pResInfo) {
188,851✔
6842
  if (pResInfo->initialized) {
188,851✔
6843
    return TSDB_CODE_SUCCESS;
82,231✔
6844
  }
6845
  if (TSDB_CODE_SUCCESS != functionSetup(pCtx, pResInfo)) {
106,620✔
6846
    return TSDB_CODE_FUNC_SETUP_ERROR;
×
6847
  }
6848

6849
  SDerivInfo* pDerivInfo = GET_ROWCELL_INTERBUF(pResInfo);
106,620✔
6850

6851
  pDerivInfo->ignoreNegative = pCtx->param[2].param.i;
106,620✔
6852
  pDerivInfo->prevTs = -1;
106,620✔
6853
  pDerivInfo->tsWindow = pCtx->param[1].param.i;
106,620✔
6854
  pDerivInfo->valueSet = false;
106,620✔
6855
  return TSDB_CODE_SUCCESS;
106,620✔
6856
}
6857

6858
int32_t derivativeFunction(SqlFunctionCtx* pCtx) { return TSDB_CODE_SUCCESS; }
107,810✔
6859

6860
static int32_t DoDerivativeFunction(SqlFunctionCtx* pCtx) {
107,810✔
6861
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
107,810✔
6862
  SDerivInfo*          pDerivInfo = GET_ROWCELL_INTERBUF(pResInfo);
107,810✔
6863

6864
  SInputColumnInfoData* pInput = &pCtx->input;
107,810✔
6865
  SColumnInfoData*      pInputCol = pInput->pData[0];
107,810✔
6866

6867
  int32_t          numOfElems = 0;
107,810✔
6868
  SColumnInfoData* pOutput = (SColumnInfoData*)pCtx->pOutput;
107,810✔
6869
  SColumnInfoData* pTsOutput = pCtx->pTsOutput;
107,810✔
6870
  int32_t          code = TSDB_CODE_SUCCESS;
107,810✔
6871

6872
  funcInputUpdate(pCtx);
107,810✔
6873

6874
  double v = 0;
107,810✔
6875
  if (pCtx->order == TSDB_ORDER_ASC) {
107,810✔
6876
    SFuncInputRow row = {0};
106,990✔
6877
    bool          result = false;
106,990✔
6878
    while (1) {
8,895,705✔
6879
      code = funcInputGetNextRow(pCtx, &row, &result);
9,002,695✔
6880
      if (TSDB_CODE_SUCCESS != code) {
9,002,695✔
6881
        return code;
×
6882
      }
6883
      if (!result) {
9,002,695✔
6884
        break;
106,990✔
6885
      }
6886
      if (row.isDataNull) {
8,895,705✔
6887
        continue;
1,344,914✔
6888
      }
6889

6890
      char* d = row.pData;
7,550,791✔
6891
      GET_TYPED_DATA(v, double, pInputCol->info.type, d, typeGetTypeModFromColInfo(&pInputCol->info));
7,550,791✔
6892

6893
      int32_t pos = pCtx->offset + numOfElems;
7,550,791✔
6894
      if (!pDerivInfo->valueSet) {  // initial value is not set yet
7,550,791✔
6895
        pDerivInfo->valueSet = true;
92,580✔
6896
      } else {
6897
        if (row.ts == pDerivInfo->prevTs) {
7,458,211✔
6898
          return TSDB_CODE_FUNC_DUP_TIMESTAMP;
×
6899
        }
6900
        double r = ((v - pDerivInfo->prevValue) * pDerivInfo->tsWindow) / (row.ts - pDerivInfo->prevTs);
7,458,211✔
6901
        if (pDerivInfo->ignoreNegative && r < 0) {
7,458,211✔
6902
        } else {
6903
          if (isinf(r) || isnan(r)) {
7,035,441✔
6904
            colDataSetNULL(pOutput, pos);
×
6905
          } else {
6906
            code = colDataSetVal(pOutput, pos, (const char*)&r, false);
7,035,441✔
6907
            if (code != TSDB_CODE_SUCCESS) {
7,035,441✔
6908
              return code;
×
6909
            }
6910
          }
6911

6912
          if (pTsOutput != NULL) {
7,035,441✔
6913
            colDataSetInt64(pTsOutput, pos, &row.ts);
×
6914
          }
6915

6916
          // handle selectivity
6917
          if (pCtx->subsidiaries.num > 0) {
7,035,441✔
6918
            code = appendSelectivityCols(pCtx, row.block, row.rowIndex, pos);
90,180✔
6919
            if (code != TSDB_CODE_SUCCESS) {
90,180✔
6920
              return code;
×
6921
            }
6922
          }
6923

6924
          numOfElems++;
7,035,441✔
6925
        }
6926
      }
6927

6928
      pDerivInfo->prevValue = v;
7,550,791✔
6929
      pDerivInfo->prevTs = row.ts;
7,550,791✔
6930
    }
6931
  } else {
6932
    SFuncInputRow row = {0};
820✔
6933
    bool          result = false;
820✔
6934
    while (1) {
1,640✔
6935
      code = funcInputGetNextRow(pCtx, &row, &result);
2,460✔
6936
      if (TSDB_CODE_SUCCESS != code) {
2,460✔
6937
        return code;
×
6938
      }
6939
      if (!result) {
2,460✔
6940
        break;
820✔
6941
      }
6942
      if (row.isDataNull) {
1,640✔
6943
        continue;
1,640✔
6944
      }
6945

6946
      char* d = row.pData;
×
6947
      GET_TYPED_DATA(v, double, pInputCol->info.type, d, typeGetTypeModFromColInfo(&pInputCol->info));
×
6948

6949
      int32_t pos = pCtx->offset + numOfElems;
×
6950
      if (!pDerivInfo->valueSet) {  // initial value is not set yet
×
6951
        pDerivInfo->valueSet = true;
×
6952
      } else {
6953
        if (row.ts == pDerivInfo->prevTs) {
×
6954
          return TSDB_CODE_FUNC_DUP_TIMESTAMP;
×
6955
        }
6956
        double r = ((pDerivInfo->prevValue - v) * pDerivInfo->tsWindow) / (pDerivInfo->prevTs - row.ts);
×
6957
        if (pDerivInfo->ignoreNegative && r < 0) {
×
6958
        } else {
6959
          if (isinf(r) || isnan(r)) {
×
6960
            colDataSetNULL(pOutput, pos);
×
6961
          } else {
6962
            code = colDataSetVal(pOutput, pos, (const char*)&r, false);
×
6963
            if (code != TSDB_CODE_SUCCESS) {
×
6964
              return code;
×
6965
            }
6966
          }
6967

6968
          if (pTsOutput != NULL) {
×
6969
            colDataSetInt64(pTsOutput, pos, &pDerivInfo->prevTs);
×
6970
          }
6971

6972
          // handle selectivity
6973
          if (pCtx->subsidiaries.num > 0) {
×
6974
            code = appendSelectivityCols(pCtx, row.block, row.rowIndex, pos);
×
6975
            if (code != TSDB_CODE_SUCCESS) {
×
6976
              return code;
×
6977
            }
6978
          }
6979
          numOfElems++;
×
6980
        }
6981
      }
6982

6983
      pDerivInfo->prevValue = v;
×
6984
      pDerivInfo->prevTs = row.ts;
×
6985
    }
6986
  }
6987

6988
  pResInfo->numOfRes = numOfElems;
107,810✔
6989

6990
  return TSDB_CODE_SUCCESS;
107,810✔
6991
}
6992

6993
int32_t derivativeFunctionByRow(SArray* pCtxArray) {
107,810✔
6994
  for (int32_t i = 0; i < taosArrayGetSize(pCtxArray); ++i) {
215,620✔
6995
    SqlFunctionCtx* pCtx = *(SqlFunctionCtx**)taosArrayGet(pCtxArray, i);
107,810✔
6996
    int32_t         code = DoDerivativeFunction(pCtx);
107,810✔
6997
    if (code != TSDB_CODE_SUCCESS) {
107,810✔
6998
      return code;
×
6999
    }
7000
  }
7001
  return TSDB_CODE_SUCCESS;
107,810✔
7002
}
7003

7004
int32_t getIrateInfoSize(int32_t pkBytes) { return (int32_t)sizeof(SRateInfo) + 2 * pkBytes; }
154,905✔
7005

7006
bool getIrateFuncEnv(struct SFunctionNode* pFunc, SFuncExecEnv* pEnv) {
116,691✔
7007
  int32_t pkBytes = (pFunc->hasPk) ? pFunc->pkBytes : 0;
116,691✔
7008
  pEnv->calcMemSize = getIrateInfoSize(pkBytes);
116,691✔
7009
  return true;
116,486✔
7010
}
7011

7012
int32_t irateFuncSetup(SqlFunctionCtx* pCtx, SResultRowEntryInfo* pResInfo) {
878,419✔
7013
  if (pResInfo->initialized) {
878,419✔
7014
    return TSDB_CODE_SUCCESS;
×
7015
  }
7016
  if (TSDB_CODE_SUCCESS != functionSetup(pCtx, pResInfo)) {
878,419✔
7017
    return TSDB_CODE_FUNC_SETUP_ERROR;
×
7018
  }
7019

7020
  SRateInfo* pInfo = GET_ROWCELL_INTERBUF(pResInfo);
878,419✔
7021

7022
  pInfo->firstKey = INT64_MIN;
878,419✔
7023
  pInfo->lastKey = INT64_MIN;
878,419✔
7024
  pInfo->firstValue = (double)INT64_MIN;
878,419✔
7025
  pInfo->lastValue = (double)INT64_MIN;
878,419✔
7026

7027
  pInfo->hasResult = 0;
878,419✔
7028
  return TSDB_CODE_SUCCESS;
878,419✔
7029
}
7030

7031
static void doSaveRateInfo(SRateInfo* pRateInfo, bool isFirst, int64_t ts, char* pk, double v) {
19,316,613✔
7032
  if (isFirst) {
19,316,613✔
7033
    pRateInfo->firstValue = v;
9,397,296✔
7034
    pRateInfo->firstKey = ts;
9,397,296✔
7035
    if (pRateInfo->firstPk) {
9,397,296✔
7036
      int32_t pkBytes;
7037
      if (IS_VAR_DATA_TYPE(pRateInfo->pkType)) {
8,085✔
7038
        pkBytes = calcStrBytesByType(pRateInfo->pkType, pk);
1,848✔
7039
      } else {
7040
        pkBytes = pRateInfo->pkBytes;
6,237✔
7041
      }
7042
      (void)memcpy(pRateInfo->firstPk, pk, pkBytes);
8,085✔
7043
    }
7044
  } else {
7045
    pRateInfo->lastValue = v;
9,919,317✔
7046
    pRateInfo->lastKey = ts;
9,919,565✔
7047
    if (pRateInfo->lastPk) {
9,919,565✔
7048
      int32_t pkBytes;
7049
      if (IS_VAR_DATA_TYPE(pRateInfo->pkType)) {
12,012✔
7050
        pkBytes = calcStrBytesByType(pRateInfo->pkType, pk);
2,772✔
7051
      } else {
7052
        pkBytes = pRateInfo->pkBytes;
9,240✔
7053
      }
7054
      (void)memcpy(pRateInfo->lastPk, pk, pkBytes);
12,012✔
7055
    }
7056
  }
7057
}
19,316,861✔
7058

7059
static void initializeRateInfo(SqlFunctionCtx* pCtx, SRateInfo* pRateInfo, bool isMerge) {
944,352✔
7060
  if (pCtx->hasPrimaryKey) {
944,352✔
7061
    if (!isMerge) {
4,389✔
7062
      pRateInfo->pkType = pCtx->input.pPrimaryKey->info.type;
3,927✔
7063
      pRateInfo->pkBytes = pCtx->input.pPrimaryKey->info.bytes;
3,927✔
7064
      pRateInfo->firstPk = pRateInfo->pkData;
3,927✔
7065
      pRateInfo->lastPk = pRateInfo->pkData + pRateInfo->pkBytes;
3,927✔
7066
    } else {
7067
      pRateInfo->firstPk = pRateInfo->pkData;
462✔
7068
      pRateInfo->lastPk = pRateInfo->pkData + pRateInfo->pkBytes;
462✔
7069
    }
7070
  } else {
7071
    pRateInfo->firstPk = NULL;
939,963✔
7072
    pRateInfo->lastPk = NULL;
939,963✔
7073
  }
7074
}
944,352✔
7075

7076
int32_t irateFunction(SqlFunctionCtx* pCtx) {
890,718✔
7077
  int32_t              code = TSDB_CODE_SUCCESS;
890,718✔
7078
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
890,718✔
7079
  SRateInfo*           pRateInfo = GET_ROWCELL_INTERBUF(pResInfo);
890,718✔
7080

7081
  SInputColumnInfoData* pInput = &pCtx->input;
890,718✔
7082
  SColumnInfoData*      pInputCol = pInput->pData[0];
890,718✔
7083

7084
  SColumnInfoData* pOutput = (SColumnInfoData*)pCtx->pOutput;
890,718✔
7085

7086
  funcInputUpdate(pCtx);
890,718✔
7087

7088
  initializeRateInfo(pCtx, pRateInfo, false);
890,718✔
7089

7090
  int32_t       numOfElems = 0;
890,718✔
7091
  int32_t       type = pInputCol->info.type;
890,718✔
7092
  SFuncInputRow row = {0};
890,718✔
7093
  bool          result = false;
890,718✔
7094
  while (1) {
13,301,513✔
7095
    code = funcInputGetNextRow(pCtx, &row, &result);
14,192,231✔
7096
    if (TSDB_CODE_SUCCESS != code) {
14,196,695✔
7097
      return code;
×
7098
    }
7099
    if (!result) {
14,196,695✔
7100
      break;
890,718✔
7101
    }
7102
    if (row.isDataNull) {
13,305,977✔
7103
      continue;
3,350,753✔
7104
    }
7105

7106
    char*  data = row.pData;
9,955,224✔
7107
    double v = 0;
9,955,224✔
7108
    GET_TYPED_DATA(v, double, type, data, typeGetTypeModFromColInfo(&pInputCol->info));
9,955,224✔
7109

7110
    if (INT64_MIN == pRateInfo->lastKey) {
9,955,224✔
7111
      doSaveRateInfo(pRateInfo, false, row.ts, row.pPk, v);
523,829✔
7112
      pRateInfo->hasResult = 1;
523,829✔
7113
      continue;
523,829✔
7114
    }
7115

7116
    if (row.ts > pRateInfo->lastKey) {
9,431,519✔
7117
      if ((INT64_MIN == pRateInfo->firstKey) || pRateInfo->lastKey > pRateInfo->firstKey) {
9,370,429✔
7118
        doSaveRateInfo(pRateInfo, true, pRateInfo->lastKey, pRateInfo->lastPk, pRateInfo->lastValue);
9,370,429✔
7119
      }
7120
      doSaveRateInfo(pRateInfo, false, row.ts, row.pPk, v);
9,370,305✔
7121
      continue;
9,370,305✔
7122
    } else if (row.ts == pRateInfo->lastKey) {
61,090✔
7123
      return TSDB_CODE_FUNC_DUP_TIMESTAMP;
×
7124
    }
7125

7126
    if ((INT64_MIN == pRateInfo->firstKey) || row.ts > pRateInfo->firstKey) {
61,090✔
7127
      doSaveRateInfo(pRateInfo, true, row.ts, row.pPk, v);
410✔
7128
    } else if (row.ts == pRateInfo->firstKey) {
60,680✔
7129
      return TSDB_CODE_FUNC_DUP_TIMESTAMP;
×
7130
    }
7131
  }
7132

7133
  numOfElems++;
890,718✔
7134

7135
  SET_VAL(pResInfo, numOfElems, 1);
890,718✔
7136
  return TSDB_CODE_SUCCESS;
890,718✔
7137
}
7138

7139
static double doCalcRate(const SRateInfo* pRateInfo, double tickPerSec) {
851,602✔
7140
  if ((INT64_MIN == pRateInfo->lastKey) || (INT64_MIN == pRateInfo->firstKey) ||
851,602✔
7141
      (pRateInfo->firstKey >= pRateInfo->lastKey)) {
70,332✔
7142
    return 0.0;
781,270✔
7143
  }
7144

7145
  double diff = 0;
70,332✔
7146
  // If the previous value of the last is greater than the last value, only keep the last point instead of the delta
7147
  // value between two values.
7148
  diff = pRateInfo->lastValue;
70,332✔
7149
  if (diff >= pRateInfo->firstValue) {
70,332✔
7150
    diff -= pRateInfo->firstValue;
51,962✔
7151
  }
7152

7153
  int64_t duration = pRateInfo->lastKey - pRateInfo->firstKey;
70,332✔
7154
  if (duration == 0) {
70,332✔
7155
    return 0;
×
7156
  }
7157

7158
  return (duration > 0) ? ((double)diff) / (duration / tickPerSec) : 0.0;
70,332✔
7159
}
7160

7161
static void irateTransferInfoImpl(TSKEY inputKey, SRateInfo* pInput, SRateInfo* pOutput, bool isFirstKey) {
23,014✔
7162
  if (inputKey > pOutput->lastKey) {
23,014✔
7163
    doSaveRateInfo(pOutput, true, pOutput->lastKey, pOutput->lastPk, pOutput->lastValue);
10,773✔
7164
    if (isFirstKey) {
10,773✔
7165
      doSaveRateInfo(pOutput, false, pInput->firstKey, pInput->firstPk, pInput->firstValue);
4,104✔
7166
    } else {
7167
      doSaveRateInfo(pOutput, false, pInput->lastKey, pInput->lastPk, pInput->lastValue);
6,669✔
7168
    }
7169
  } else if ((inputKey < pOutput->lastKey) && (inputKey > pOutput->firstKey)) {
12,241✔
7170
    if (isFirstKey) {
1,026✔
7171
      doSaveRateInfo(pOutput, true, pInput->firstKey, pInput->firstPk, pInput->firstValue);
513✔
7172
    } else {
7173
      doSaveRateInfo(pOutput, true, pInput->lastKey, pInput->lastPk, pInput->lastValue);
513✔
7174
    }
7175
  } else {
7176
    // inputKey < pOutput->firstKey
7177
  }
7178
}
23,014✔
7179

7180
static void irateCopyInfo(SRateInfo* pInput, SRateInfo* pOutput) {
14,658✔
7181
  doSaveRateInfo(pOutput, true, pInput->firstKey, pInput->firstPk, pInput->firstValue);
14,658✔
7182
  doSaveRateInfo(pOutput, false, pInput->lastKey, pInput->lastPk, pInput->lastValue);
14,658✔
7183
}
14,658✔
7184

7185
static int32_t irateTransferInfo(SRateInfo* pInput, SRateInfo* pOutput) {
26,165✔
7186
  if ((pInput->firstKey != INT64_MIN &&
26,165✔
7187
       (pInput->firstKey == pOutput->firstKey || pInput->firstKey == pOutput->lastKey)) ||
23,245✔
7188
      (pInput->lastKey != INT64_MIN && (pInput->lastKey == pOutput->firstKey || pInput->lastKey == pOutput->lastKey))) {
26,165✔
7189
    return TSDB_CODE_FUNC_DUP_TIMESTAMP;
×
7190
  }
7191

7192
  if (pOutput->hasResult == 0) {
26,165✔
7193
    irateCopyInfo(pInput, pOutput);
14,658✔
7194
    pOutput->hasResult = pInput->hasResult;
14,658✔
7195
    return TSDB_CODE_SUCCESS;
14,658✔
7196
  }
7197

7198
  if (pInput->firstKey != INT64_MIN) {
11,507✔
7199
    irateTransferInfoImpl(pInput->firstKey, pInput, pOutput, true);
11,507✔
7200
  }
7201

7202
  if (pInput->lastKey != INT64_MIN) {
11,507✔
7203
    irateTransferInfoImpl(pInput->lastKey, pInput, pOutput, false);
11,507✔
7204
  }
7205

7206
  pOutput->hasResult = pInput->hasResult;
11,507✔
7207
  return TSDB_CODE_SUCCESS;
11,507✔
7208
}
7209

7210
int32_t irateFunctionMerge(SqlFunctionCtx* pCtx) {
26,817✔
7211
  SInputColumnInfoData* pInput = &pCtx->input;
26,817✔
7212
  SColumnInfoData*      pCol = pInput->pData[0];
26,817✔
7213
  if (pCol->info.type != TSDB_DATA_TYPE_BINARY) {
26,817✔
7214
    return TSDB_CODE_FUNC_FUNTION_PARA_TYPE;
×
7215
  }
7216

7217
  SRateInfo* pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
26,817✔
7218
  initializeRateInfo(pCtx, pInfo, true);
26,817✔
7219

7220
  int32_t start = pInput->startRowIndex;
26,817✔
7221
  for (int32_t i = start; i < start + pInput->numOfRows; ++i) {
53,634✔
7222
    char*      data = colDataGetData(pCol, i);
26,817✔
7223
    SRateInfo* pInputInfo = (SRateInfo*)varDataVal(data);
26,817✔
7224
    initializeRateInfo(pCtx, pInfo, true);
26,817✔
7225
    if (pInputInfo->hasResult) {
26,817✔
7226
      int32_t code = irateTransferInfo(pInputInfo, pInfo);
26,165✔
7227
      if (code != TSDB_CODE_SUCCESS) {
26,165✔
7228
        return code;
×
7229
      }
7230
    }
7231
  }
7232

7233
  if (pInfo->hasResult) {
26,817✔
7234
    GET_RES_INFO(pCtx)->numOfRes = 1;
26,165✔
7235
  }
7236

7237
  return TSDB_CODE_SUCCESS;
26,817✔
7238
}
7239

7240
int32_t iratePartialFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
26,817✔
7241
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
26,817✔
7242
  SRateInfo*           pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
26,817✔
7243
  int32_t              resultBytes = getIrateInfoSize(pInfo->pkBytes);
26,817✔
7244
  char*                res = taosMemoryCalloc(resultBytes + VARSTR_HEADER_SIZE, sizeof(char));
26,817✔
7245

7246
  if (NULL == res) {
26,817✔
7247
    return terrno;
×
7248
  }
7249
  (void)memcpy(varDataVal(res), pInfo, resultBytes);
26,817✔
7250
  varDataSetLen(res, resultBytes);
26,817✔
7251

7252
  int32_t          slotId = pCtx->pExpr->base.resSchema.slotId;
26,817✔
7253
  SColumnInfoData* pCol = taosArrayGet(pBlock->pDataBlock, slotId);
26,817✔
7254
  if (NULL == pCol) {
26,817✔
7255
    taosMemoryFree(res);
×
7256
    return TSDB_CODE_OUT_OF_RANGE;
×
7257
  }
7258

7259
  int32_t code = colDataSetVal(pCol, pBlock->info.rows, res, false);
26,817✔
7260

7261
  taosMemoryFree(res);
26,817✔
7262
  return code;
26,817✔
7263
}
7264

7265
int32_t irateFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
851,602✔
7266
  int32_t          slotId = pCtx->pExpr->base.resSchema.slotId;
851,602✔
7267
  SColumnInfoData* pCol = taosArrayGet(pBlock->pDataBlock, slotId);
851,602✔
7268
  if (NULL == pCol) {
851,602✔
7269
    return TSDB_CODE_OUT_OF_RANGE;
×
7270
  }
7271

7272
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
851,602✔
7273
  pResInfo->isNullRes = (pResInfo->numOfRes == 0) ? 1 : 0;
851,602✔
7274

7275
  SRateInfo* pInfo = GET_ROWCELL_INTERBUF(pResInfo);
851,602✔
7276
  double     result = doCalcRate(pInfo, (double)TSDB_TICK_PER_SECOND(pCtx->param[1].param.i));
851,602✔
7277
  int32_t    code = colDataSetVal(pCol, pBlock->info.rows, (const char*)&result, pResInfo->isNullRes);
851,602✔
7278

7279
  return code;
851,602✔
7280
}
7281

7282
int32_t groupConstValueFunction(SqlFunctionCtx* pCtx) {
2,147,483,647✔
7283
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
2,147,483,647✔
7284
  SGroupKeyInfo*       pInfo    = GET_ROWCELL_INTERBUF(pResInfo);
2,147,483,647✔
7285
  bool                 isWindow = pCtx->hasWindowOrGroup && pCtx->hasWindow;
2,147,483,647✔
7286

7287
  if (pInfo->hasResult && (!isWindow || !pInfo->isNull)) {
2,147,483,647✔
7288
    // If already has result for 'group by' or 
7289
    // has non-null result for 'window', we can skip left data blocks.
7290
    goto _group_value_over;
1,230,164,402✔
7291
  }
7292

7293
  int32_t               valueRowIndex = -1;
2,147,483,647✔
7294
  SInputColumnInfoData* pInput        = &pCtx->input;
2,147,483,647✔
7295
  SColumnInfoData*      pInputCol     = pInput->pData[0];
2,147,483,647✔
7296

7297
  // try to find a non-null value
7298
  if (NULL != pInputCol->pData) {
2,147,483,647✔
7299
    if (isWindow) {
2,147,483,647✔
7300
      // for 'window', non-null value can appear at any row of any data block
7301
      int64_t startIndex = pInput->startRowIndex;
2,147,483,647✔
7302
      int64_t endIndex   = pInput->startRowIndex + pInput->numOfRows - 1;
2,147,483,647✔
7303
      for (int64_t i = startIndex; i <= endIndex; ++i) {
2,147,483,647✔
7304
        if (!colDataIsNull_s(pInputCol, i)) {
2,147,483,647✔
7305
          valueRowIndex = i;
2,147,483,647✔
7306
          break;
2,147,483,647✔
7307
        }
7308
      }
7309
    } else {
7310
      // for 'group by', just take the first row
7311
      if (!colDataIsNull_s(pInputCol, pInput->startRowIndex)) {
295,028,723✔
7312
        valueRowIndex = pInput->startRowIndex;
144,549,354✔
7313
      }
7314
    }
7315
  }
7316

7317
  if (valueRowIndex != -1) {
2,147,483,647✔
7318
    // found a non-null value
7319
    char* data = colDataGetData(pInputCol, valueRowIndex);
2,147,483,647✔
7320
    if (IS_VAR_DATA_TYPE(pInputCol->info.type)) {
2,147,483,647✔
7321
      int32_t bytes = calcStrBytesByType(pInputCol->info.type, data);
2,140,958,795✔
7322
      (void)memcpy(pInfo->data, data, bytes);
2,140,846,772✔
7323
    } else {
7324
      (void)memcpy(pInfo->data, data, pInputCol->info.bytes);
888,358,495✔
7325
    }
7326
    pInfo->isNull = false;
2,147,483,647✔
7327
  } else {
7328
    // all values are null or first value is null for group by
7329
    pInfo->isNull = true;
73,679,973✔
7330
  }
7331
  pInfo->hasResult = true;
2,147,483,647✔
7332

7333
_group_value_over:
2,147,483,647✔
7334
  SET_VAL(pResInfo, 1, 1);
2,147,483,647✔
7335
  return TSDB_CODE_SUCCESS;
2,147,483,647✔
7336
}
7337

7338
int32_t groupKeyFunction(SqlFunctionCtx* pCtx) { return groupConstValueFunction(pCtx); }
2,147,483,647✔
7339

7340
int32_t groupConstValueFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
2,147,483,647✔
7341
  int32_t          slotId = pCtx->pExpr->base.resSchema.slotId;
2,147,483,647✔
7342
  int32_t          code = TSDB_CODE_SUCCESS;
2,147,483,647✔
7343
  SColumnInfoData* pCol = taosArrayGet(pBlock->pDataBlock, slotId);
2,147,483,647✔
7344
  if (NULL == pCol) {
2,147,483,647✔
7345
    return TSDB_CODE_OUT_OF_RANGE;
×
7346
  }
7347

7348
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
2,147,483,647✔
7349

7350
  SGroupKeyInfo* pInfo = GET_ROWCELL_INTERBUF(pResInfo);
2,147,483,647✔
7351

7352
  if (pInfo->hasResult) {
2,147,483,647✔
7353
    int32_t currentRow = pBlock->info.rows;
2,147,483,647✔
7354
    for (; currentRow < pBlock->info.rows + pResInfo->numOfRes; ++currentRow) {
2,147,483,647✔
7355
      code = colDataSetVal(pCol, currentRow, pInfo->data, pInfo->isNull ? true : false);
2,147,483,647✔
7356
      if (TSDB_CODE_SUCCESS != code) {
2,147,483,647✔
7357
        return code;
×
7358
      }
7359
    }
7360
  } else {
7361
    pResInfo->numOfRes = 0;
×
7362
  }
7363

7364
  return code;
2,147,483,647✔
7365
}
7366

7367
int32_t groupKeyFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) { return groupConstValueFinalize(pCtx, pBlock); }
2,147,483,647✔
7368

7369
int32_t groupKeyCombine(SqlFunctionCtx* pDestCtx, SqlFunctionCtx* pSourceCtx) {
×
7370
  SResultRowEntryInfo* pDResInfo = GET_RES_INFO(pDestCtx);
×
7371
  SGroupKeyInfo*       pDBuf = GET_ROWCELL_INTERBUF(pDResInfo);
×
7372

7373
  SResultRowEntryInfo* pSResInfo = GET_RES_INFO(pSourceCtx);
×
7374
  SGroupKeyInfo*       pSBuf = GET_ROWCELL_INTERBUF(pSResInfo);
×
7375

7376
  // escape rest of data blocks to avoid first entry to be overwritten.
7377
  if (pDBuf->hasResult) {
×
7378
    goto _group_key_over;
×
7379
  }
7380

7381
  if (pSBuf->isNull) {
×
7382
    pDBuf->isNull = true;
×
7383
    pDBuf->hasResult = true;
×
7384
    goto _group_key_over;
×
7385
  }
7386

7387
  if (IS_VAR_DATA_TYPE(pSourceCtx->resDataInfo.type)) {
×
7388
    int32_t bytes = calcStrBytesByType(pSourceCtx->resDataInfo.type, pSBuf->data);
×
7389
    (void)memcpy(pDBuf->data, pSBuf->data, bytes);
×
7390
  } else {
7391
    (void)memcpy(pDBuf->data, pSBuf->data, pSourceCtx->resDataInfo.bytes);
×
7392
  }
7393

7394
  pDBuf->hasResult = true;
×
7395

7396
_group_key_over:
×
7397

7398
  SET_VAL(pDResInfo, 1, 1);
×
7399
  return TSDB_CODE_SUCCESS;
×
7400
}
7401

7402
int32_t cachedLastRowFunction(SqlFunctionCtx* pCtx) {
479,398✔
7403
  int32_t numOfElems = 0;
479,398✔
7404

7405
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
479,398✔
7406
  SFirstLastRes*       pInfo = GET_ROWCELL_INTERBUF(pResInfo);
479,398✔
7407

7408
  SInputColumnInfoData* pInput = &pCtx->input;
479,398✔
7409
  SColumnInfoData*      pInputCol = pInput->pData[0];
479,398✔
7410

7411
  int32_t bytes = pInputCol->info.bytes;
479,398✔
7412
  pInfo->bytes = bytes;
479,398✔
7413

7414
  SColumnInfoData* pkCol = pInput->pPrimaryKey;
479,398✔
7415
  pInfo->pkType = -1;
479,398✔
7416
  __compar_fn_t pkCompareFn = NULL;
479,398✔
7417
  if (pCtx->hasPrimaryKey) {
479,398✔
7418
    pInfo->pkType = pkCol->info.type;
18,444✔
7419
    pInfo->pkBytes = pkCol->info.bytes;
18,444✔
7420
    pkCompareFn = getKeyComparFunc(pInfo->pkType, TSDB_ORDER_DESC);
18,444✔
7421
  }
7422

7423
  // data is guaranteed to be in descending order
7424
  for (int32_t i = pInput->numOfRows + pInput->startRowIndex - 1; i >= pInput->startRowIndex; --i) {
1,025,289✔
7425
    numOfElems++;
545,891✔
7426

7427
    bool  isNull = colDataIsNull(pInputCol, pInput->numOfRows, i, NULL);
545,891✔
7428
    char* data = isNull ? NULL : colDataGetData(pInputCol, i);
545,891✔
7429

7430
    TSKEY cts = getRowPTs(pInput->pPTS, i);
545,891✔
7431
    if (pResInfo->numOfRes == 0 || pInfo->ts < cts) {
545,891✔
7432
      int32_t code = doSaveLastrow(pCtx, data, i, cts, pInfo);
441,388✔
7433
      if (code != TSDB_CODE_SUCCESS) {
441,388✔
7434
        return code;
×
7435
      }
7436
      pResInfo->numOfRes = 1;
441,388✔
7437
    }
7438
  }
7439

7440
  SET_VAL(pResInfo, numOfElems, 1);
479,398✔
7441
  return TSDB_CODE_SUCCESS;
479,398✔
7442
}
7443

7444
bool getCorrFuncEnv(SFunctionNode* pFunc, SFuncExecEnv* pEnv) {
×
7445
  pEnv->calcMemSize = sizeof(SCorrRes);
×
7446
  return true;
×
7447
}
7448

7449
int32_t corrFuncSetup(SqlFunctionCtx* pCtx, SResultRowEntryInfo* pResultInfo) {
×
7450
  if (pResultInfo->initialized) {
×
7451
    return TSDB_CODE_SUCCESS;
×
7452
  }
7453
  if (TSDB_CODE_SUCCESS != functionSetup(pCtx, pResultInfo)) {
×
7454
    return TSDB_CODE_FUNC_SETUP_ERROR;
×
7455
  }
7456

7457
  SCorrRes* pRes = GET_ROWCELL_INTERBUF(pResultInfo);
×
7458
  (void)memset(pRes, 0, sizeof(SCorrRes));
×
7459
  return TSDB_CODE_SUCCESS;
×
7460
}
7461

7462
int32_t corrFunction(SqlFunctionCtx* pCtx) {
×
7463
  int32_t               numOfElem = 0;
×
7464
  SInputColumnInfoData* pInput = &pCtx->input;
×
7465
  int32_t               xType = pInput->pData[0]->info.type;
×
7466
  int32_t               yType = pInput->pData[1]->info.type;
×
7467
  SCorrRes*             pCorrRes = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
×
7468

7469
  // computing based on the true data block
7470
  SColumnInfoData* pLeft = pInput->pData[0];  // left
×
7471
  SColumnInfoData* pRight = pInput->pData[1]; // right
×
7472

7473
  int32_t leftMod = typeGetTypeModFromColInfo(&pLeft->info);
×
7474
  int32_t rightMod = typeGetTypeModFromColInfo(&pRight->info);
×
7475
  int32_t start = pInput->startRowIndex;
×
7476
  int32_t numOfRows = pInput->numOfRows;
×
7477

7478
  if (IS_NULL_TYPE(xType) || IS_NULL_TYPE(yType)) {
×
7479
    numOfElem = 0;
×
7480
    goto _over;
×
7481
  }
7482
  
7483
  for(int32_t i = 0; i < numOfRows; ++i) {
×
7484
    double pInputX = 0, pInputY = 0;
×
7485

7486
    if (colDataIsNull_f(pLeft, i) || colDataIsNull_f(pRight, i)) {
×
7487
      continue;
×
7488
    }
7489

7490
    char*  pXVal = colDataGetData(pLeft, i);
×
7491
    char*  pYVal = colDataGetData(pRight, i);
×
7492

7493
    GET_TYPED_DATA(pInputX, double, xType, pXVal, leftMod);
×
7494
    GET_TYPED_DATA(pInputY, double, yType, pYVal, rightMod);
×
7495

7496
    pCorrRes->sumLeft += pInputX;
×
7497
    pCorrRes->sumRight += pInputY;
×
7498

7499
    pCorrRes->quadLeft += pInputX * pInputX;
×
7500
    pCorrRes->quadRight += pInputY * pInputY;
×
7501

7502
    pCorrRes->productVal += pInputX * pInputY;
×
7503

7504
    pCorrRes->count += 1;
×
7505
    numOfElem += 1;
×
7506
  }
7507

7508
_over:
×
7509
  // data in the check operation are all null, not output
7510
  SET_VAL(GET_RES_INFO(pCtx), numOfElem, 1);
×
7511
  return TSDB_CODE_SUCCESS;
×
7512
}
7513

7514
int32_t corrFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
×
7515
  SInputColumnInfoData* pInput = &pCtx->input;
×
7516
  SCorrRes*             pRes = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
×
7517
  double                avg;
7518

7519
  if (pRes->count == 0) {
×
7520
    GET_RES_INFO(pCtx)->numOfRes = 0;
×
7521
    return functionFinalize(pCtx, pBlock);
×
7522
  }
7523

7524
  /**
7525
    numerator = sum_xy - (sum_x * sum_y) / n
7526
    denominator_x = math.sqrt(sum_x2 - (sum_x**2) / n)
7527
    denominator_y = math.sqrt(sum_y2 - (sum_y**2) / n)
7528
    
7529
    if denominator_x == 0 or denominator_y == 0:
7530
        return 0.0
7531
    res = numerator / (denominator_x * denominator_y)
7532
  */
7533

7534
  if (pRes->count == 1) {
×
7535
    pRes->result = 0.0;
×
7536
  } else {
7537
    double numerator = pRes->productVal - (pRes->sumLeft * pRes->sumRight) / pRes->count;
×
7538
    double dnmX = sqrt(pRes->quadLeft - pRes->sumLeft * pRes->sumLeft/pRes->count);
×
7539
    double dnmY = sqrt(pRes->quadRight - pRes->sumRight * pRes->sumRight/pRes->count);  
×
7540

7541
    if (DBL_EQUAL(dnmX, 0.0) || DBL_EQUAL(dnmY, 0.0)) {
×
7542
      pRes->result = 0.0;
×
7543
    } else {
7544
      pRes->result = numerator / (dnmX * dnmY);
×
7545

7546
      if (pRes->result > 1 || pRes->result < -1) {
×
7547
        qError("invalid corr results, %.4f, numerator:%.4f, dnmX:%.4f, dnmY:%.4f", pRes->result, numerator, dnmX, dnmY);
×
7548
        if (pRes->result > 1) {
×
7549
          pRes->result = 1;
×
7550
        } else if (pRes->result < -1) {
×
7551
          pRes->result = -1;
×
7552
        }
7553
      }
7554
    }
7555
  }
7556

7557
  return functionFinalize(pCtx, pBlock);
×
7558
}
7559

7560
int32_t getCorrInfoSize() {return sizeof(SCorrRes);}
×
7561

7562
int32_t corrPartialFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
×
7563
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
×
7564
  SStdRes*             pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
×
7565
  int32_t              resultBytes = getCorrInfoSize();
×
7566
  char*                res = taosMemoryCalloc(resultBytes + VARSTR_HEADER_SIZE, sizeof(char));
×
7567
  int32_t              slotId = pCtx->pExpr->base.resSchema.slotId;
×
7568
  int32_t              code = 0;
×
7569

7570
  if (NULL == res) {
×
7571
    return terrno;
×
7572
  }
7573
  
7574
  (void)memcpy(varDataVal(res), pInfo, resultBytes);
×
7575
  varDataSetLen(res, resultBytes);
×
7576

7577
  SColumnInfoData* pCol = taosArrayGet(pBlock->pDataBlock, slotId);
×
7578
  if (NULL == pCol) {
×
7579
    taosMemoryFree(res);
×
7580
    return TSDB_CODE_OUT_OF_RANGE;
×
7581
  }
7582

7583
  code = colDataSetVal(pCol, pBlock->info.rows, res, false);
×
7584

7585
  taosMemoryFree(res);
×
7586
  return code;
×
7587
}
7588

7589
int32_t corrFuncMerge(SqlFunctionCtx* pCtx) {
×
7590
  SInputColumnInfoData* pInput = &pCtx->input;
×
7591
  SColumnInfoData*      pCol = pInput->pData[0];
×
7592

7593
  if (IS_NULL_TYPE(pCol->info.type)) {
×
7594
    SET_VAL(GET_RES_INFO(pCtx), 0, 1);
×
7595
    return TSDB_CODE_SUCCESS;
×
7596
  }
7597

7598
  if (pCol->info.type != TSDB_DATA_TYPE_BINARY) {
×
7599
    return TSDB_CODE_FUNC_FUNTION_PARA_TYPE;
×
7600
  }
7601

7602
  SCorrRes* pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
×
7603

7604
  for (int32_t i = pInput->startRowIndex; i < pInput->startRowIndex + pInput->numOfRows; ++i) {
×
7605
    if (colDataIsNull_s(pCol, i)) {
×
7606
      continue;
×
7607
    }
7608

7609
    char*     data = colDataGetData(pCol, i);
×
7610
    SCorrRes* pInputInfo = (SCorrRes*)varDataVal(data);
×
7611

7612
    if (pInputInfo->count == 0) {
×
7613
      continue;
×
7614
    }
7615

7616
    // pOutput->type = pInput->type;
7617
    if (pInfo->count == 0) {
×
7618
      TAOS_MEMCPY(pInfo, pInputInfo, sizeof(SCorrRes));
×
7619
    } else if (pInfo->count > 0) {
×
7620
      pInfo->productVal += pInputInfo->productVal;
×
7621
      pInfo->quadLeft += pInputInfo->quadLeft;
×
7622
      pInfo->quadRight += pInputInfo->quadRight;
×
7623
      pInfo->sumLeft += pInputInfo->sumLeft;
×
7624
      pInfo->sumRight += pInputInfo->sumRight;
×
7625
      pInfo->count += pInputInfo->count;
×
7626
    }
7627
  }
7628

7629
  SET_VAL(GET_RES_INFO(pCtx), pInfo->count, 1);
×
7630
  return TSDB_CODE_SUCCESS;
×
7631
}
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