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

taosdata / TDengine / #3658

14 Mar 2025 08:10AM UTC coverage: 63.25% (+0.4%) from 62.877%
#3658

push

travis-ci

web-flow
feat(keep): support keep on super table level. (#30097)

* Feat: support use keep while create super table.

* Test(keep): add test for create super table with keep option.

* Feat(keep): Add tmsg for create keep.

* Feat(keep): support alter table option keep.

* Fix(keep): Add baisc test for alter table option.

* Fix(keep): memory leek.

* Feat(keep): add keep to metaEntry&metaCache and fix earliestTs with stn keep.

* Test(keep): add some cases for select with stb keep.

* Fix: fix ci core while alter stb.

* Feat(keep): delete expired data in super table level.

* Feat: remove get stb keep while query.

* Fix : build error.

* Revert "Fix : build error."

This reverts commit 0ed66e4e8.

* Revert "Feat(keep): delete expired data in super table level."

This reverts commit 36330f6b4.

* Fix : build errors.

* Feat : support restart taosd.

* Fix : alter table comment problems.

* Test : add tests for super table keep.

* Fix: change sdb stb reserve size.

* Test: add more tests.

* Feat: Disable normal tables and sub tables from setting the keep parameter

* Fix: add more checks to avoid unknown address.

* Docs: Add docs for stable keep.

* Fix: some review changes.

* Fix: review errors.

148878 of 302527 branches covered (49.21%)

Branch coverage included in aggregate %.

88 of 99 new or added lines in 12 files covered. (88.89%)

3290 existing lines in 68 files now uncovered.

234027 of 302857 relevant lines covered (77.27%)

17847433.29 hits per line

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

72.39
/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 "function.h"
19
#include "functionResInfoInt.h"
20
#include "query.h"
21
#include "querynodes.h"
22
#include "tanalytics.h"
23
#include "tcompare.h"
24
#include "tdatablock.h"
25
#include "tdigest.h"
26
#include "tfunctionInt.h"
27
#include "tglobal.h"
28
#include "thistogram.h"
29
#include "tpercentile.h"
30

31
bool ignoreNegative(int8_t ignoreOption) { return (ignoreOption & 0x1) == 0x1; }
1,615,825,394✔
32
bool ignoreNull(int8_t ignoreOption) { return (ignoreOption & 0x2) == 0x2; }
1,951,822✔
33

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

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

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

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

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

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

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

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

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

108
#define LIST_SUB_N(_res, _col, _start, _rows, _t, numOfElem)             \
109
  do {                                                                   \
110
    _t* d = (_t*)(_col->pData);                                          \
111
    for (int32_t i = (_start); i < (_rows) + (_start); ++i) {            \
112
      if (((_col)->hasNull) && colDataIsNull_f((_col)->nullbitmap, i)) { \
113
        continue;                                                        \
114
      };                                                                 \
115
      (_res) -= (d)[i];                                                  \
116
      (numOfElem)++;                                                     \
117
    }                                                                    \
118
  } while (0)
119

120
//#define LIST_AVG_N(sumT, T)                                               \
121
//  do {                                                                    \
122
//    T* plist = (T*)pCol->pData;                                           \
123
//    for (int32_t i = start; i < numOfRows + pInput->startRowIndex; ++i) { \
124
//      if (pCol->hasNull && colDataIsNull_f(pCol->nullbitmap, i)) {        \
125
//        continue;                                                         \
126
//      }                                                                   \
127
//                                                                          \
128
//      numOfElem += 1;                                                     \
129
//      pAvgRes->count -= 1;                                                \
130
//      sumT -= plist[i];                                                   \
131
//    }                                                                     \
132
//  } while (0)
133

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

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

157
#define STATE_COMP(_op, _lval, _param) STATE_COMP_IMPL(_op, _lval, GET_STATE_VAL(_param))
158

159
#define GET_STATE_VAL(param) ((param.nType == TSDB_DATA_TYPE_BIGINT) ? (param.i) : (param.d))
160

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

187
#define INIT_INTP_POINT(_p, _k, _v) \
188
  do {                              \
189
    (_p).key = (_k);                \
190
    (_p).val = (_v);                \
191
  } while (0)
192

193
void funcInputUpdate(SqlFunctionCtx* pCtx) {
20,525,503✔
194
  SFuncInputRowIter* pIter = &pCtx->rowIter;
20,525,503✔
195

196
  if (!pCtx->bInputFinished) {
20,525,503!
197
    pIter->pInput = &pCtx->input;
20,525,538✔
198
    pIter->tsList = (TSKEY*)pIter->pInput->pPTS->pData;
20,525,538✔
199
    pIter->pDataCol = pIter->pInput->pData[0];
20,525,538✔
200
    pIter->pPkCol = pIter->pInput->pPrimaryKey;
20,525,538✔
201
    pIter->rowIndex = pIter->pInput->startRowIndex;
20,525,538✔
202
    pIter->inputEndIndex = pIter->rowIndex + pIter->pInput->numOfRows - 1;
20,525,538✔
203
    pIter->pSrcBlock = pCtx->pSrcBlock;
20,525,538✔
204
    if (!pIter->hasGroupId || pIter->groupId != pIter->pSrcBlock->info.id.groupId) {
20,525,538✔
205
      pIter->hasGroupId = true;
226,185✔
206
      pIter->groupId = pIter->pSrcBlock->info.id.groupId;
226,185✔
207
      pIter->hasPrev = false;
226,185✔
208
    }
209
  } else {
210
    pIter->finalRow = true;
×
211
  }
212
}
20,525,503✔
213

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

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

239
      pIter->prevIsDataNull = colDataIsNull_f(pIter->pDataCol->nullbitmap, pIter->inputEndIndex);
×
240

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

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

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

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

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

328
static void forwardToNextDiffTsRow(SFuncInputRowIter* pIter, int32_t rowIndex) {
160✔
329
  int32_t idx = rowIndex + 1;
160✔
330
  while (idx <= pIter->inputEndIndex && pIter->tsList[idx] == pIter->tsList[rowIndex]) {
362!
331
    ++idx;
202✔
332
  }
333
  pIter->rowIndex = idx;
160✔
334
}
160✔
335

336
static void setInputRowInfo(SFuncInputRow* pRow, SFuncInputRowIter* pIter, int32_t rowIndex, bool setPk) {
1,660,695,528✔
337
  pRow->ts = pIter->tsList[rowIndex];
1,660,695,528✔
338
  pRow->ts = pIter->tsList[rowIndex];
1,660,695,528✔
339
  pRow->isDataNull = colDataIsNull_f(pIter->pDataCol->nullbitmap, rowIndex);
1,660,695,528✔
340
  pRow->pData = colDataGetData(pIter->pDataCol, rowIndex);
1,660,695,528!
341
  pRow->pPk = setPk ? colDataGetData(pIter->pPkCol, rowIndex) : NULL;
1,660,695,528!
342
  pRow->block = pIter->pSrcBlock;
1,660,695,528✔
343
  pRow->rowIndex = rowIndex;
1,660,695,528✔
344
}
1,660,695,528✔
345

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

357
      pIter->hasPrev = false;
×
358
      setInputRowInfo(pRow, pIter, idx, true);
×
359
      forwardToNextDiffTsRow(pIter, idx);
×
360
      return true;
×
361
    }
362
  } else {
363
    if (pIter->rowIndex <= pIter->inputEndIndex) {
330✔
364
      setInputRowInfo(pRow, pIter, pIter->rowIndex, true);
248✔
365

366
      TSKEY tsEnd = pIter->tsList[pIter->inputEndIndex];
248✔
367
      if (pIter->tsList[pIter->rowIndex] != tsEnd) {
248✔
368
        forwardToNextDiffTsRow(pIter, pIter->rowIndex);
160✔
369
      } else {
370
        pIter->rowIndex = pIter->inputEndIndex + 1;
88✔
371
      }
372
      return true;
248✔
373
    } else {
374
      TSKEY tsEnd = pIter->tsList[pIter->inputEndIndex];
82✔
375
      pIter->hasPrev = true;
82✔
376
      pIter->prevBlockTsEnd = tsEnd;
82✔
377
      return false;
82✔
378
    }
379
  }
380
}
381

382
bool funcInputGetNextRowNoPk(SFuncInputRowIter* pIter, SFuncInputRow* pRow) {
1,681,086,456✔
383
  if (pIter->rowIndex <= pIter->inputEndIndex) {
1,681,086,456✔
384
    setInputRowInfo(pRow, pIter, pIter->rowIndex, false);
1,660,714,044✔
385
    ++pIter->rowIndex;
1,660,575,381✔
386
    return true;
1,660,575,381✔
387
  } else {
388
    return false;
20,372,412✔
389
  }
390
}
391

392
int32_t funcInputGetNextRow(SqlFunctionCtx* pCtx, SFuncInputRow* pRow, bool* res) {
1,681,116,306✔
393
  SFuncInputRowIter* pIter = &pCtx->rowIter;
1,681,116,306✔
394
  if (pCtx->hasPrimaryKey) {
1,681,116,306✔
395
    if (pCtx->order == TSDB_ORDER_ASC) {
330!
396
      *res = funcInputGetNextRowAscPk(pIter, pRow);
330✔
397
      return TSDB_CODE_SUCCESS;
330✔
398
    } else {
399
      return funcInputGetNextRowDescPk(pIter, pRow, res);
×
400
    }
401
  } else {
402
    *res = funcInputGetNextRowNoPk(pIter, pRow);
1,681,115,976✔
403
    return TSDB_CODE_SUCCESS;
1,680,924,918✔
404
  }
405
  return TSDB_CODE_SUCCESS;
406
}
407

408
// This function append the selectivity to subsidiaries function context directly, without fetching data
409
// from intermediate disk based buf page
410
int32_t appendSelectivityCols(SqlFunctionCtx* pCtx, SSDataBlock* pSrcBlock, int32_t rowIndex, int32_t pos) {
35,693,142✔
411
  if (pCtx->subsidiaries.num <= 0) {
35,693,142!
412
    return TSDB_CODE_SUCCESS;
×
413
  }
414

415
  for (int32_t j = 0; j < pCtx->subsidiaries.num; ++j) {
71,385,797✔
416
    SqlFunctionCtx* pc = pCtx->subsidiaries.pCtx[j];
35,693,071✔
417

418
    // get data from source col
419
    SFunctParam* pFuncParam = &pc->pExpr->base.pParam[0];
35,693,071✔
420
    int32_t      srcSlotId = pFuncParam->pCol->slotId;
35,693,071✔
421

422
    SColumnInfoData* pSrcCol = taosArrayGet(pSrcBlock->pDataBlock, srcSlotId);
35,693,071✔
423
    if (NULL == pSrcCol) {
35,692,793!
424
      return TSDB_CODE_OUT_OF_RANGE;
×
425
    }
426

427
    char* pData = colDataGetData(pSrcCol, rowIndex);
35,692,793!
428

429
    // append to dest col
430
    int32_t dstSlotId = pc->pExpr->base.resSchema.slotId;
35,692,793✔
431

432
    SColumnInfoData* pDstCol = taosArrayGet(pCtx->pDstBlock->pDataBlock, dstSlotId);
35,692,793✔
433
    if (NULL == pDstCol) {
35,692,529!
434
      return TSDB_CODE_OUT_OF_RANGE;
×
435
    }
436
    if (colDataIsNull_s(pSrcCol, rowIndex) == true) {
71,385,058✔
437
      colDataSetNULL(pDstCol, pos);
20!
438
    } else {
439
      int32_t code = colDataSetVal(pDstCol, pos, pData, false);
35,692,509✔
440
      if (TSDB_CODE_SUCCESS != code) {
35,692,635!
441
        return code;
×
442
      }
443
    }
444
  }
445
  return TSDB_CODE_SUCCESS;
35,692,726✔
446
}
447

448
bool funcInputGetNextRowIndex(SInputColumnInfoData* pInput, int32_t from, bool firstOccur, int32_t* pRowIndex,
449
                              int32_t* nextFrom);
450

451
static bool firstLastTransferInfoImpl(SFirstLastRes* pInput, SFirstLastRes* pOutput, bool isFirst);
452

453
int32_t functionSetup(SqlFunctionCtx* pCtx, SResultRowEntryInfo* pResultInfo) {
699,553,041✔
454
  if (pResultInfo->initialized) {
699,553,041✔
455
    return TSDB_CODE_SUCCESS;  // already initialized
167,635✔
456
  }
457

458
  if (pCtx->pOutput != NULL) {
699,385,406!
459
    (void)memset(pCtx->pOutput, 0, (size_t)pCtx->resDataInfo.bytes);
×
460
  }
461

462
  initResultRowEntry(pResultInfo, pCtx->resDataInfo.interBufSize);
699,385,406✔
463
  return TSDB_CODE_SUCCESS;
699,385,406✔
464
}
465

466
int32_t functionFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
189,907,804✔
467
  int32_t          code = TSDB_CODE_SUCCESS;
189,907,804✔
468
  int32_t          slotId = pCtx->pExpr->base.resSchema.slotId;
189,907,804✔
469
  SColumnInfoData* pCol = taosArrayGet(pBlock->pDataBlock, slotId);
189,907,804✔
470
  if (NULL == pCol) {
189,401,498!
471
    return TSDB_CODE_OUT_OF_RANGE;
×
472
  }
473
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
189,401,498✔
474
  pResInfo->isNullRes = (pResInfo->numOfRes == 0) ? 1 : 0;
189,401,498✔
475

476
  char* in = GET_ROWCELL_INTERBUF(pResInfo);
189,401,498✔
477
  code = colDataSetVal(pCol, pBlock->info.rows, in, pResInfo->isNullRes);
189,401,498✔
478

479
  return code;
190,856,790✔
480
}
481

482
int32_t firstCombine(SqlFunctionCtx* pDestCtx, SqlFunctionCtx* pSourceCtx) {
3✔
483
  SResultRowEntryInfo* pDResInfo = GET_RES_INFO(pDestCtx);
3✔
484
  SFirstLastRes*       pDBuf = GET_ROWCELL_INTERBUF(pDResInfo);
3✔
485
  int32_t              bytes = pDBuf->bytes;
3✔
486

487
  SResultRowEntryInfo* pSResInfo = GET_RES_INFO(pSourceCtx);
3✔
488
  SFirstLastRes*       pSBuf = GET_ROWCELL_INTERBUF(pSResInfo);
3✔
489

490
  pDBuf->hasResult = firstLastTransferInfoImpl(pSBuf, pDBuf, true);
3✔
491

492
  pDResInfo->numOfRes = TMAX(pDResInfo->numOfRes, pSResInfo->numOfRes);
3✔
493
  pDResInfo->isNullRes &= pSResInfo->isNullRes;
3✔
494
  return TSDB_CODE_SUCCESS;
3✔
495
}
496

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

506
  char*   in = finalResult;
39✔
507
  int32_t code = colDataSetVal(pCol, pBlock->info.rows, in, pResInfo->isNullRes);
39✔
508

509
  return code;
39✔
510
}
511

512
EFuncDataRequired countDataRequired(SFunctionNode* pFunc, STimeWindow* pTimeWindow) {
218,012✔
513
  SNode* pParam = nodesListGetNode(pFunc->pParameterList, 0);
218,012✔
514
  if (QUERY_NODE_COLUMN == nodeType(pParam) && PRIMARYKEY_TIMESTAMP_COL_ID == ((SColumnNode*)pParam)->colId) {
218,046!
515
    return FUNC_DATA_REQUIRED_NOT_LOAD;
159,840✔
516
  }
517
  return FUNC_DATA_REQUIRED_SMA_LOAD;
58,206✔
518
}
519

520
bool getCountFuncEnv(SFunctionNode* UNUSED_PARAM(pFunc), SFuncExecEnv* pEnv) {
1,747,671✔
521
  pEnv->calcMemSize = sizeof(int64_t);
1,747,671✔
522
  return true;
1,747,671✔
523
}
524

525
static int64_t getNumOfElems(SqlFunctionCtx* pCtx) {
119,392,283✔
526
  int64_t numOfElem = 0;
119,392,283✔
527

528
  /*
529
   * 1. column data missing (schema modified) causes pInputCol->hasNull == true. pInput->colDataSMAIsSet == true;
530
   * 2. for general non-primary key columns, pInputCol->hasNull may be true or false, pInput->colDataSMAIsSet == true;
531
   * 3. for primary key column, pInputCol->hasNull always be false, pInput->colDataSMAIsSet == false;
532
   */
533
  SInputColumnInfoData* pInput = &pCtx->input;
119,392,283✔
534
  SColumnInfoData*      pInputCol = pInput->pData[0];
119,392,283✔
535
  if (1 == pInput->numOfRows && pInput->blankFill) {
119,392,283✔
536
    return 0;
444,670✔
537
  }
538
  if (pInput->colDataSMAIsSet && pInput->totalRows == pInput->numOfRows) {
118,947,613!
539
    numOfElem = pInput->numOfRows - pInput->pColumnDataAgg[0]->numOfNull;
4,098✔
540
  } else {
541
    if (pInputCol->hasNull) {
118,943,515✔
542
      for (int32_t i = pInput->startRowIndex; i < pInput->startRowIndex + pInput->numOfRows; ++i) {
408,034,806✔
543
        if (colDataIsNull(pInputCol, pInput->totalRows, i, NULL)) {
751,980,608!
544
          continue;
2,333,686✔
545
        }
546
        numOfElem += 1;
373,656,618✔
547
      }
548
    } else {
549
      // when counting on the primary time stamp column and no statistics data is presented, use the size value
550
      // directly.
551
      numOfElem = pInput->numOfRows;
86,899,013✔
552
    }
553
  }
554
  return numOfElem;
118,947,613✔
555
}
556

557
/*
558
 * count function does need the finalize, if data is missing, the default value, which is 0, is used
559
 * count function does not use the pCtx->interResBuf to keep the intermediate buffer
560
 */
561
int32_t countFunction(SqlFunctionCtx* pCtx) {
119,668,316✔
562
  int64_t numOfElem = 0;
119,668,316✔
563

564
  SResultRowEntryInfo*  pResInfo = GET_RES_INFO(pCtx);
119,668,316✔
565
  SInputColumnInfoData* pInput = &pCtx->input;
119,668,316✔
566

567
  int32_t type = pInput->pData[0]->info.type;
119,668,316✔
568

569
  char*   buf = GET_ROWCELL_INTERBUF(pResInfo);
119,668,316✔
570
  int64_t val = *((int64_t*)buf);
119,668,316✔
571
  if (IS_NULL_TYPE(type)) {
119,668,316✔
572
    // select count(NULL) returns 0
573
    numOfElem = 1;
137,011✔
574
    val += 0;
137,011✔
575
  } else {
576
    numOfElem = getNumOfElems(pCtx);
119,531,305✔
577
    val += numOfElem;
119,027,559✔
578
  }
579
  taosSetInt64Aligned((int64_t*)buf, val);
580

581
  if (tsCountAlwaysReturnValue) {
119,164,570!
582
    pResInfo->numOfRes = 1;
119,421,299✔
583
  } else {
584
    SET_VAL(pResInfo, val, 1);
×
585
  }
586

587
  return TSDB_CODE_SUCCESS;
119,164,570✔
588
}
589

590
#ifdef BUILD_NO_CALL
591
int32_t countInvertFunction(SqlFunctionCtx* pCtx) {
592
  int64_t numOfElem = getNumOfElems(pCtx);
593

594
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
595
  char*                buf = GET_ROWCELL_INTERBUF(pResInfo);
596
  *((int64_t*)buf) -= numOfElem;
597

598
  SET_VAL(pResInfo, *((int64_t*)buf), 1);
599
  return TSDB_CODE_SUCCESS;
600
}
601
#endif
602

603
int32_t combineFunction(SqlFunctionCtx* pDestCtx, SqlFunctionCtx* pSourceCtx) {
18✔
604
  SResultRowEntryInfo* pDResInfo = GET_RES_INFO(pDestCtx);
18✔
605
  char*                pDBuf = GET_ROWCELL_INTERBUF(pDResInfo);
18✔
606

607
  SResultRowEntryInfo* pSResInfo = GET_RES_INFO(pSourceCtx);
18✔
608
  char*                pSBuf = GET_ROWCELL_INTERBUF(pSResInfo);
18✔
609
  *((int64_t*)pDBuf) += *((int64_t*)pSBuf);
18✔
610

611
  SET_VAL(pDResInfo, *((int64_t*)pDBuf), 1);
18!
612
  return TSDB_CODE_SUCCESS;
18✔
613
}
614

615
int32_t sumFunction(SqlFunctionCtx* pCtx) {
89,572,634✔
616
  int32_t numOfElem = 0;
89,572,634✔
617

618
  // Only the pre-computing information loaded and actual data does not loaded
619
  SInputColumnInfoData* pInput = &pCtx->input;
89,572,634✔
620
  SColumnDataAgg*       pAgg = pInput->pColumnDataAgg[0];
89,572,634✔
621
  int32_t               type = pInput->pData[0]->info.type;
89,572,634✔
622

623
  SSumRes* pSumRes = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
89,572,634✔
624
  pSumRes->type = type;
89,572,634✔
625

626
  if (IS_NULL_TYPE(type)) {
89,572,634✔
627
    numOfElem = 0;
199✔
628
    goto _sum_over;
199✔
629
  }
630

631
  if (pInput->colDataSMAIsSet) {
89,572,435✔
632
    numOfElem = pInput->numOfRows - pAgg->numOfNull;
2,572✔
633

634
    if (IS_SIGNED_NUMERIC_TYPE(type)) {
2,572!
635
      pSumRes->isum += pAgg->sum;
2,572✔
636
    } else if (IS_UNSIGNED_NUMERIC_TYPE(type)) {
×
637
      pSumRes->usum += pAgg->sum;
×
638
    } else if (IS_FLOAT_TYPE(type)) {
×
639
      pSumRes->dsum += GET_DOUBLE_VAL((const char*)&(pAgg->sum));
×
640
    }
641
  } else {  // computing based on the true data block
642
    SColumnInfoData* pCol = pInput->pData[0];
89,569,863✔
643

644
    int32_t start = pInput->startRowIndex;
89,569,863✔
645
    int32_t numOfRows = pInput->numOfRows;
89,569,863✔
646

647
    if (IS_SIGNED_NUMERIC_TYPE(type) || type == TSDB_DATA_TYPE_BOOL) {
89,569,863!
648
      if (type == TSDB_DATA_TYPE_TINYINT || type == TSDB_DATA_TYPE_BOOL) {
88,700,397!
649
        LIST_ADD_N(pSumRes->isum, pCol, start, numOfRows, int8_t, numOfElem);
1,712,790✔
650
      } else if (type == TSDB_DATA_TYPE_SMALLINT) {
88,340,586✔
651
        LIST_ADD_N(pSumRes->isum, pCol, start, numOfRows, int16_t, numOfElem);
6,197,449✔
652
      } else if (type == TSDB_DATA_TYPE_INT) {
86,426,101✔
653
        LIST_ADD_N(pSumRes->isum, pCol, start, numOfRows, int32_t, numOfElem);
394,690,068✔
654
      } else if (type == TSDB_DATA_TYPE_BIGINT) {
21,035,814✔
655
        LIST_ADD_N(pSumRes->isum, pCol, start, numOfRows, int64_t, numOfElem);
78,464,323✔
656
      }
657
    } else if (IS_UNSIGNED_NUMERIC_TYPE(type)) {
869,466!
658
      if (type == TSDB_DATA_TYPE_UTINYINT) {
202✔
659
        LIST_ADD_N(pSumRes->usum, pCol, start, numOfRows, uint8_t, numOfElem);
130,039!
660
      } else if (type == TSDB_DATA_TYPE_USMALLINT) {
163✔
661
        LIST_ADD_N(pSumRes->usum, pCol, start, numOfRows, uint16_t, numOfElem);
130,047✔
662
      } else if (type == TSDB_DATA_TYPE_UINT) {
123✔
663
        LIST_ADD_N(pSumRes->usum, pCol, start, numOfRows, uint32_t, numOfElem);
130,039!
664
      } else if (type == TSDB_DATA_TYPE_UBIGINT) {
84!
665
        LIST_ADD_N(pSumRes->usum, pCol, start, numOfRows, uint64_t, numOfElem);
130,624✔
666
      }
667
    } else if (type == TSDB_DATA_TYPE_DOUBLE) {
869,264✔
668
      LIST_ADD_N(pSumRes->dsum, pCol, start, numOfRows, double, numOfElem);
2,512,640✔
669
    } else if (type == TSDB_DATA_TYPE_FLOAT) {
768,169✔
670
      LIST_ADD_N(pSumRes->dsum, pCol, start, numOfRows, float, numOfElem);
1,858,413✔
671
    }
672
  }
673

674
  // check for overflow
675
  if (IS_FLOAT_TYPE(type) && (isinf(pSumRes->dsum) || isnan(pSumRes->dsum))) {
89,572,435!
676
    numOfElem = 0;
×
677
  }
678

679
_sum_over:
90,055,268✔
680
  if (numOfElem == 0) {
89,572,634✔
681
    if (tsCountAlwaysReturnValue && pCtx->pExpr->pExpr->_function.pFunctNode->hasOriginalFunc &&
89,393✔
682
        fmIsCountLikeFunc(pCtx->pExpr->pExpr->_function.pFunctNode->originalFuncId)) {
11,593✔
683
      numOfElem = 1;
18✔
684
    }
685
  }
686
  // data in the check operation are all null, not output
687
  SET_VAL(GET_RES_INFO(pCtx), numOfElem, 1);
89,572,634✔
688
  return TSDB_CODE_SUCCESS;
89,572,634✔
689
}
690

691
#ifdef BUILD_NO_CALL
692
int32_t sumInvertFunction(SqlFunctionCtx* pCtx) {
693
  int32_t numOfElem = 0;
694

695
  // Only the pre-computing information loaded and actual data does not loaded
696
  SInputColumnInfoData* pInput = &pCtx->input;
697
  SColumnDataAgg*       pAgg = pInput->pColumnDataAgg[0];
698
  int32_t               type = pInput->pData[0]->info.type;
699

700
  SSumRes* pSumRes = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
701

702
  if (pInput->colDataSMAIsSet) {
703
    numOfElem = pInput->numOfRows - pAgg->numOfNull;
704

705
    if (IS_SIGNED_NUMERIC_TYPE(type)) {
706
      pSumRes->isum -= pAgg->sum;
707
    } else if (IS_UNSIGNED_NUMERIC_TYPE(type)) {
708
      pSumRes->usum -= pAgg->sum;
709
    } else if (IS_FLOAT_TYPE(type)) {
710
      pSumRes->dsum -= GET_DOUBLE_VAL((const char*)&(pAgg->sum));
711
    }
712
  } else {  // computing based on the true data block
713
    SColumnInfoData* pCol = pInput->pData[0];
714

715
    int32_t start = pInput->startRowIndex;
716
    int32_t numOfRows = pInput->numOfRows;
717

718
    if (IS_SIGNED_NUMERIC_TYPE(type) || type == TSDB_DATA_TYPE_BOOL) {
719
      if (type == TSDB_DATA_TYPE_TINYINT || type == TSDB_DATA_TYPE_BOOL) {
720
        LIST_SUB_N(pSumRes->isum, pCol, start, numOfRows, int8_t, numOfElem);
721
      } else if (type == TSDB_DATA_TYPE_SMALLINT) {
722
        LIST_SUB_N(pSumRes->isum, pCol, start, numOfRows, int16_t, numOfElem);
723
      } else if (type == TSDB_DATA_TYPE_INT) {
724
        LIST_SUB_N(pSumRes->isum, pCol, start, numOfRows, int32_t, numOfElem);
725
      } else if (type == TSDB_DATA_TYPE_BIGINT) {
726
        LIST_SUB_N(pSumRes->isum, pCol, start, numOfRows, int64_t, numOfElem);
727
      }
728
    } else if (IS_UNSIGNED_NUMERIC_TYPE(type)) {
729
      if (type == TSDB_DATA_TYPE_UTINYINT) {
730
        LIST_SUB_N(pSumRes->usum, pCol, start, numOfRows, uint8_t, numOfElem);
731
      } else if (type == TSDB_DATA_TYPE_USMALLINT) {
732
        LIST_SUB_N(pSumRes->usum, pCol, start, numOfRows, uint16_t, numOfElem);
733
      } else if (type == TSDB_DATA_TYPE_UINT) {
734
        LIST_SUB_N(pSumRes->usum, pCol, start, numOfRows, uint32_t, numOfElem);
735
      } else if (type == TSDB_DATA_TYPE_UBIGINT) {
736
        LIST_SUB_N(pSumRes->usum, pCol, start, numOfRows, uint64_t, numOfElem);
737
      }
738
    } else if (type == TSDB_DATA_TYPE_DOUBLE) {
739
      LIST_SUB_N(pSumRes->dsum, pCol, start, numOfRows, double, numOfElem);
740
    } else if (type == TSDB_DATA_TYPE_FLOAT) {
741
      LIST_SUB_N(pSumRes->dsum, pCol, start, numOfRows, float, numOfElem);
742
    }
743
  }
744

745
  // data in the check operation are all null, not output
746
  SET_VAL(GET_RES_INFO(pCtx), numOfElem, 1);
747
  return TSDB_CODE_SUCCESS;
748
}
749
#endif
750

751
int32_t sumCombine(SqlFunctionCtx* pDestCtx, SqlFunctionCtx* pSourceCtx) {
35✔
752
  SResultRowEntryInfo* pDResInfo = GET_RES_INFO(pDestCtx);
35✔
753
  SSumRes*             pDBuf = GET_ROWCELL_INTERBUF(pDResInfo);
35✔
754

755
  SResultRowEntryInfo* pSResInfo = GET_RES_INFO(pSourceCtx);
35✔
756
  SSumRes*             pSBuf = GET_ROWCELL_INTERBUF(pSResInfo);
35✔
757
  int16_t              type = pDBuf->type == TSDB_DATA_TYPE_NULL ? pSBuf->type : pDBuf->type;
35✔
758

759
  if (IS_SIGNED_NUMERIC_TYPE(type) || type == TSDB_DATA_TYPE_BOOL) {
35!
760
    pDBuf->isum += pSBuf->isum;
35✔
761
  } else if (IS_UNSIGNED_NUMERIC_TYPE(type)) {
×
762
    pDBuf->usum += pSBuf->usum;
×
763
  } else if (type == TSDB_DATA_TYPE_DOUBLE || type == TSDB_DATA_TYPE_FLOAT) {
×
764
    pDBuf->dsum += pSBuf->dsum;
×
765
  }
766
  pDResInfo->numOfRes = TMAX(pDResInfo->numOfRes, pSResInfo->numOfRes);
35✔
767
  pDResInfo->isNullRes &= pSResInfo->isNullRes;
35✔
768
  return TSDB_CODE_SUCCESS;
35✔
769
}
770

771
bool getSumFuncEnv(SFunctionNode* UNUSED_PARAM(pFunc), SFuncExecEnv* pEnv) {
242,773✔
772
  pEnv->calcMemSize = sizeof(SSumRes);
242,773✔
773
  return true;
242,773✔
774
}
775

776
static bool funcNotSupportStringSma(SFunctionNode* pFunc) {
186,874✔
777
  SNode* pParam;
778
  switch (pFunc->funcType) {
186,874!
779
    case FUNCTION_TYPE_MAX:
186,874✔
780
    case FUNCTION_TYPE_MIN:
781
    case FUNCTION_TYPE_SUM:
782
    case FUNCTION_TYPE_AVG:
783
    case FUNCTION_TYPE_AVG_PARTIAL:
784
    case FUNCTION_TYPE_PERCENTILE:
785
    case FUNCTION_TYPE_SPREAD:
786
    case FUNCTION_TYPE_SPREAD_PARTIAL:
787
    case FUNCTION_TYPE_SPREAD_MERGE:
788
    case FUNCTION_TYPE_TWA:
789
    case FUNCTION_TYPE_ELAPSED:
790
      pParam = nodesListGetNode(pFunc->pParameterList, 0);
186,874✔
791
      if (pParam && nodesIsExprNode(pParam) && (IS_VAR_DATA_TYPE(((SExprNode*)pParam)->resType.type))) {
186,874!
792
        return true;
126✔
793
      }
794
      break;
186,748✔
795
    default:
×
796
      break;
×
797
  }
798
  return false;
186,748✔
799
}
800

801
EFuncDataRequired statisDataRequired(SFunctionNode* pFunc, STimeWindow* pTimeWindow) {
186,874✔
802
  if (funcNotSupportStringSma(pFunc)) {
186,874✔
803
    return FUNC_DATA_REQUIRED_DATA_LOAD;
126✔
804
  }
805
  return FUNC_DATA_REQUIRED_SMA_LOAD;
186,748✔
806
}
807

808
int32_t minmaxFunctionSetup(SqlFunctionCtx* pCtx, SResultRowEntryInfo* pResultInfo) {
48,188,987✔
809
  if (pResultInfo->initialized) {
48,188,987!
810
    return TSDB_CODE_SUCCESS;
×
811
  }
812
  if (TSDB_CODE_SUCCESS != functionSetup(pCtx, pResultInfo)) {
48,188,987!
813
    return TSDB_CODE_FUNC_SETUP_ERROR;  // not initialized since it has been initialized
×
814
  }
815

816
  SMinmaxResInfo* buf = GET_ROWCELL_INTERBUF(pResultInfo);
48,194,551✔
817
  buf->assign = false;
48,194,551✔
818
  buf->tuplePos.pageId = -1;
48,194,551✔
819

820
  buf->nullTupleSaved = false;
48,194,551✔
821
  buf->nullTuplePos.pageId = -1;
48,194,551✔
822
  buf->str = NULL;
48,194,551✔
823
  return TSDB_CODE_SUCCESS;
48,194,551✔
824
}
825

826
bool getMinmaxFuncEnv(SFunctionNode* UNUSED_PARAM(pFunc), SFuncExecEnv* pEnv) {
421,226✔
827
  pEnv->calcMemSize = sizeof(SMinmaxResInfo);
421,226✔
828
  return true;
421,226✔
829
}
830

831
int32_t minFunction(SqlFunctionCtx* pCtx) {
24,391,176✔
832
  int32_t numOfElems = 0;
24,391,176✔
833
  int32_t code = doMinMaxHelper(pCtx, 1, &numOfElems);
24,391,176✔
834
  if (code != TSDB_CODE_SUCCESS) {
24,451,717!
835
    return code;
×
836
  }
837
  SET_VAL(GET_RES_INFO(pCtx), numOfElems, 1);
24,451,717✔
838
  return TSDB_CODE_SUCCESS;
24,451,717✔
839
}
840

841
int32_t maxFunction(SqlFunctionCtx* pCtx) {
27,428,195✔
842
  int32_t numOfElems = 0;
27,428,195✔
843
  int32_t code = doMinMaxHelper(pCtx, 0, &numOfElems);
27,428,195✔
844
  if (code != TSDB_CODE_SUCCESS) {
27,466,687!
845
    return code;
×
846
  }
847
  SET_VAL(GET_RES_INFO(pCtx), numOfElems, 1);
27,466,687✔
848
  return TSDB_CODE_SUCCESS;
27,466,687✔
849
}
850

851
static int32_t setNullSelectivityValue(SqlFunctionCtx* pCtx, SSDataBlock* pBlock, int32_t rowIndex);
852
static int32_t setSelectivityValue(SqlFunctionCtx* pCtx, SSDataBlock* pBlock, const STuplePos* pTuplePos,
853
                                   int32_t rowIndex);
854

855
int32_t minmaxFunctionFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
46,356,606✔
856
  int32_t code = TSDB_CODE_SUCCESS;
46,356,606✔
857

858
  SResultRowEntryInfo* pEntryInfo = GET_RES_INFO(pCtx);
46,356,606✔
859
  SMinmaxResInfo*      pRes = GET_ROWCELL_INTERBUF(pEntryInfo);
46,356,606✔
860

861
  int32_t slotId = pCtx->pExpr->base.resSchema.slotId;
46,356,606✔
862
  int32_t currentRow = pBlock->info.rows;
46,356,606✔
863

864
  SColumnInfoData* pCol = taosArrayGet(pBlock->pDataBlock, slotId);
46,356,606✔
865
  if (NULL == pCol) {
46,365,262!
866
    return TSDB_CODE_OUT_OF_RANGE;
×
867
  }
868
  pEntryInfo->isNullRes = (pEntryInfo->numOfRes == 0) ? 1 : 0;
46,365,262✔
869

870
  // NOTE: do nothing change it, for performance issue
871
  if (!pEntryInfo->isNullRes) {
46,365,262✔
872
    switch (pCol->info.type) {
39,761,864!
873
      case TSDB_DATA_TYPE_UBIGINT:
8,945,497✔
874
      case TSDB_DATA_TYPE_BIGINT:
875
        ((int64_t*)pCol->pData)[currentRow] = pRes->v;
8,945,497✔
876
        break;
8,945,497✔
877
      case TSDB_DATA_TYPE_UINT:
21,469,822✔
878
      case TSDB_DATA_TYPE_INT:
879
        colDataSetInt32(pCol, currentRow, (int32_t*)&pRes->v);
21,469,822✔
880
        break;
21,469,822✔
881
      case TSDB_DATA_TYPE_USMALLINT:
3,078,305✔
882
      case TSDB_DATA_TYPE_SMALLINT:
883
        colDataSetInt16(pCol, currentRow, (int16_t*)&pRes->v);
3,078,305✔
884
        break;
3,078,305✔
885
      case TSDB_DATA_TYPE_BOOL:
216,689✔
886
      case TSDB_DATA_TYPE_UTINYINT:
887
      case TSDB_DATA_TYPE_TINYINT:
888
        colDataSetInt8(pCol, currentRow, (int8_t*)&pRes->v);
216,689✔
889
        break;
216,689✔
890
      case TSDB_DATA_TYPE_DOUBLE:
4,406✔
891
        colDataSetDouble(pCol, currentRow, (double*)&pRes->v);
4,406✔
892
        break;
4,406✔
893
      case TSDB_DATA_TYPE_FLOAT: {
3,073,099✔
894
        float v = GET_FLOAT_VAL(&pRes->v);
3,073,099✔
895
        colDataSetFloat(pCol, currentRow, &v);
3,073,099✔
896
        break;
3,073,099✔
897
      }
898
      case TSDB_DATA_TYPE_VARBINARY:
2,990,072✔
899
      case TSDB_DATA_TYPE_VARCHAR:
900
      case TSDB_DATA_TYPE_NCHAR: {
901
        code = colDataSetVal(pCol, currentRow, pRes->str, false);
2,990,072✔
902
        if (TSDB_CODE_SUCCESS != code) {
2,990,072!
903
          return code;
×
904
        }
905
        break;
2,990,072✔
906
      }
907
    }
908
  } else {
909
    colDataSetNULL(pCol, currentRow);
6,603,398!
910
  }
911

912
  taosMemoryFreeClear(pRes->str);
46,365,262!
913
  if (pCtx->subsidiaries.num > 0) {
46,365,262✔
914
    if (pEntryInfo->numOfRes > 0) {
11,347,026✔
915
      code = setSelectivityValue(pCtx, pBlock, &pRes->tuplePos, currentRow);
11,344,216✔
916
    } else {
917
      code = setNullSelectivityValue(pCtx, pBlock, currentRow);
2,810✔
918
    }
919
  }
920

921
  return code;
46,368,069✔
922
}
923

924
int32_t setNullSelectivityValue(SqlFunctionCtx* pCtx, SSDataBlock* pBlock, int32_t rowIndex) {
2,391,949✔
925
  if (pCtx->subsidiaries.num <= 0) {
2,391,949✔
926
    return TSDB_CODE_SUCCESS;
2,389,098✔
927
  }
928

929
  for (int32_t j = 0; j < pCtx->subsidiaries.num; ++j) {
7,241✔
930
    SqlFunctionCtx* pc = pCtx->subsidiaries.pCtx[j];
4,390✔
931
    int32_t         dstSlotId = pc->pExpr->base.resSchema.slotId;
4,390✔
932

933
    SColumnInfoData* pDstCol = taosArrayGet(pBlock->pDataBlock, dstSlotId);
4,390✔
934
    if (NULL == pDstCol) {
4,390!
935
      return terrno;
×
936
    }
937
    colDataSetNULL(pDstCol, rowIndex);
4,390✔
938
  }
939

940
  return TSDB_CODE_SUCCESS;
2,851✔
941
}
942

943
int32_t setSelectivityValue(SqlFunctionCtx* pCtx, SSDataBlock* pBlock, const STuplePos* pTuplePos, int32_t rowIndex) {
239,429,280✔
944
  if (pCtx->subsidiaries.num <= 0) {
239,429,280✔
945
    return TSDB_CODE_SUCCESS;
101,616,134✔
946
  }
947

948
  if ((pCtx->saveHandle.pBuf != NULL && pTuplePos->pageId != -1) ||
137,813,146!
UNCOV
949
      (pCtx->saveHandle.pState && pTuplePos->streamTupleKey.ts > 0)) {
×
950
    int32_t numOfCols = pCtx->subsidiaries.num;
137,815,203✔
951
    char*   p = NULL;
137,815,203✔
952
    int32_t code = loadTupleData(pCtx, pTuplePos, &p);
137,815,203✔
953
    if (p == NULL || TSDB_CODE_SUCCESS != code) {
138,240,365!
954
      qError("Load tuple data failed since %s, groupId:%" PRIu64 ", ts:%" PRId64, terrstr(),
×
955
             pTuplePos->streamTupleKey.groupId, pTuplePos->streamTupleKey.ts);
956
      return TSDB_CODE_NOT_FOUND;
×
957
    }
958

959
    bool* nullList = (bool*)p;
138,241,543✔
960
    char* pStart = (char*)(nullList + numOfCols * sizeof(bool));
138,241,543✔
961

962
    // todo set the offset value to optimize the performance.
963
    for (int32_t j = 0; j < numOfCols; ++j) {
276,260,656✔
964
      SqlFunctionCtx* pc = pCtx->subsidiaries.pCtx[j];
138,252,048✔
965
      int32_t         dstSlotId = pc->pExpr->base.resSchema.slotId;
138,252,048✔
966

967
      SColumnInfoData* pDstCol = taosArrayGet(pBlock->pDataBlock, dstSlotId);
138,252,048✔
968
      if (NULL == pDstCol) {
138,154,584!
969
        return terrno;
×
970
      }
971
      if (nullList[j]) {
138,156,008✔
972
        colDataSetNULL(pDstCol, rowIndex);
152!
973
      } else {
974
        code = colDataSetValOrCover(pDstCol, rowIndex, pStart, false);
138,155,856✔
975
        if (TSDB_CODE_SUCCESS != code) {
138,018,961!
976
          return code;
×
977
        }
978
      }
979
      pStart += pDstCol->info.bytes;
138,019,113✔
980
    }
981
  }
982

983
  return TSDB_CODE_SUCCESS;
138,006,551✔
984
}
985

986
// This function append the selectivity to subsidiaries function context directly, without fetching data
987
// from intermediate disk based buf page
988
int32_t appendSelectivityValue(SqlFunctionCtx* pCtx, int32_t rowIndex, int32_t pos) {
55,866,107✔
989
  if (pCtx->subsidiaries.num <= 0) {
55,866,107!
990
    return TSDB_CODE_SUCCESS;
×
991
  }
992

993
  int32_t code = TSDB_CODE_SUCCESS;
55,866,107✔
994
  for (int32_t j = 0; j < pCtx->subsidiaries.num; ++j) {
111,705,343✔
995
    SqlFunctionCtx* pc = pCtx->subsidiaries.pCtx[j];
55,868,094✔
996

997
    // get data from source col
998
    SFunctParam* pFuncParam = &pc->pExpr->base.pParam[0];
55,868,094✔
999
    int32_t      srcSlotId = pFuncParam->pCol->slotId;
55,868,094✔
1000

1001
    SColumnInfoData* pSrcCol = taosArrayGet(pCtx->pSrcBlock->pDataBlock, srcSlotId);
55,868,094✔
1002
    if (NULL == pSrcCol) {
55,848,077!
1003
      return TSDB_CODE_OUT_OF_RANGE;
×
1004
    }
1005

1006
    char* pData = colDataGetData(pSrcCol, rowIndex);
55,848,077!
1007

1008
    // append to dest col
1009
    int32_t dstSlotId = pc->pExpr->base.resSchema.slotId;
55,848,077✔
1010

1011
    SColumnInfoData* pDstCol = taosArrayGet(pCtx->pDstBlock->pDataBlock, dstSlotId);
55,848,077✔
1012
    if (NULL == pDstCol) {
55,823,386!
1013
      return TSDB_CODE_OUT_OF_RANGE;
×
1014
    }
1015

1016
    if (colDataIsNull_s(pSrcCol, rowIndex) == true) {
111,646,772✔
1017
      colDataSetNULL(pDstCol, pos);
400✔
1018
    } else {
1019
      code = colDataSetVal(pDstCol, pos, pData, false);
55,822,986✔
1020
      if (TSDB_CODE_SUCCESS != code) {
55,838,836!
1021
        return code;
×
1022
      }
1023
    }
1024
  }
1025
  return code;
55,837,249✔
1026
}
1027

1028
void replaceTupleData(STuplePos* pDestPos, STuplePos* pSourcePos) { *pDestPos = *pSourcePos; }
27✔
1029

1030
#define COMPARE_MINMAX_DATA(type) (((*(type*)&pDBuf->v) < (*(type*)&pSBuf->v)) ^ isMinFunc)
1031
int32_t minMaxCombine(SqlFunctionCtx* pDestCtx, SqlFunctionCtx* pSourceCtx, int32_t isMinFunc) {
51✔
1032
  SResultRowEntryInfo* pDResInfo = GET_RES_INFO(pDestCtx);
51✔
1033
  SMinmaxResInfo*      pDBuf = GET_ROWCELL_INTERBUF(pDResInfo);
51✔
1034

1035
  SResultRowEntryInfo* pSResInfo = GET_RES_INFO(pSourceCtx);
51✔
1036
  SMinmaxResInfo*      pSBuf = GET_ROWCELL_INTERBUF(pSResInfo);
51✔
1037
  int16_t              type = pDBuf->type == TSDB_DATA_TYPE_NULL ? pSBuf->type : pDBuf->type;
51✔
1038

1039
  switch (type) {
51!
1040
    case TSDB_DATA_TYPE_DOUBLE:
3✔
1041
    case TSDB_DATA_TYPE_UBIGINT:
1042
    case TSDB_DATA_TYPE_BIGINT:
1043
      if (pSBuf->assign && (COMPARE_MINMAX_DATA(int64_t) || !pDBuf->assign)) {
3!
1044
        pDBuf->v = pSBuf->v;
1✔
1045
        replaceTupleData(&pDBuf->tuplePos, &pSBuf->tuplePos);
1✔
1046
        pDBuf->assign = true;
1✔
1047
      }
1048
      break;
3✔
1049
    case TSDB_DATA_TYPE_UINT:
48✔
1050
    case TSDB_DATA_TYPE_INT:
1051
      if (pSBuf->assign && (COMPARE_MINMAX_DATA(int32_t) || !pDBuf->assign)) {
48!
1052
        pDBuf->v = pSBuf->v;
26✔
1053
        replaceTupleData(&pDBuf->tuplePos, &pSBuf->tuplePos);
26✔
1054
        pDBuf->assign = true;
26✔
1055
      }
1056
      break;
48✔
1057
    case TSDB_DATA_TYPE_USMALLINT:
×
1058
    case TSDB_DATA_TYPE_SMALLINT:
1059
      if (pSBuf->assign && (COMPARE_MINMAX_DATA(int16_t) || !pDBuf->assign)) {
×
1060
        pDBuf->v = pSBuf->v;
×
1061
        replaceTupleData(&pDBuf->tuplePos, &pSBuf->tuplePos);
×
1062
        pDBuf->assign = true;
×
1063
      }
1064
      break;
×
1065
    case TSDB_DATA_TYPE_BOOL:
×
1066
    case TSDB_DATA_TYPE_UTINYINT:
1067
    case TSDB_DATA_TYPE_TINYINT:
1068
      if (pSBuf->assign && (COMPARE_MINMAX_DATA(int8_t) || !pDBuf->assign)) {
×
1069
        pDBuf->v = pSBuf->v;
×
1070
        replaceTupleData(&pDBuf->tuplePos, &pSBuf->tuplePos);
×
1071
        pDBuf->assign = true;
×
1072
      }
1073
      break;
×
1074
    case TSDB_DATA_TYPE_FLOAT: {
×
1075
      if (pSBuf->assign && (COMPARE_MINMAX_DATA(double) || !pDBuf->assign)) {
×
1076
        pDBuf->v = pSBuf->v;
×
1077
        replaceTupleData(&pDBuf->tuplePos, &pSBuf->tuplePos);
×
1078
        pDBuf->assign = true;
×
1079
      }
1080
      break;
×
1081
    }
1082
    default:
×
1083
      if (pSBuf->assign && (strcmp((char*)&pDBuf->v, (char*)&pSBuf->v) || !pDBuf->assign)) {
×
1084
        pDBuf->v = pSBuf->v;
×
1085
        replaceTupleData(&pDBuf->tuplePos, &pSBuf->tuplePos);
×
1086
        pDBuf->assign = true;
×
1087
      }
1088
      break;
×
1089
  }
1090
  pDResInfo->numOfRes = TMAX(pDResInfo->numOfRes, pSResInfo->numOfRes);
51✔
1091
  pDResInfo->isNullRes &= pSResInfo->isNullRes;
51✔
1092
  return TSDB_CODE_SUCCESS;
51✔
1093
}
1094

1095
int32_t minCombine(SqlFunctionCtx* pDestCtx, SqlFunctionCtx* pSourceCtx) {
11✔
1096
  return minMaxCombine(pDestCtx, pSourceCtx, 1);
11✔
1097
}
1098
int32_t maxCombine(SqlFunctionCtx* pDestCtx, SqlFunctionCtx* pSourceCtx) {
40✔
1099
  return minMaxCombine(pDestCtx, pSourceCtx, 0);
40✔
1100
}
1101

1102
int32_t getStdInfoSize() { return (int32_t)sizeof(SStdRes); }
988,484✔
1103

1104
bool getStdFuncEnv(SFunctionNode* pFunc, SFuncExecEnv* pEnv) {
158,700✔
1105
  pEnv->calcMemSize = sizeof(SStdRes);
158,700✔
1106
  return true;
158,700✔
1107
}
1108

1109
int32_t stdFunctionSetup(SqlFunctionCtx* pCtx, SResultRowEntryInfo* pResultInfo) {
7,710,548✔
1110
  if (pResultInfo->initialized) {
7,710,548!
1111
    return TSDB_CODE_SUCCESS;
×
1112
  }
1113
  if (TSDB_CODE_SUCCESS != functionSetup(pCtx, pResultInfo)) {
7,710,548!
1114
    return TSDB_CODE_FUNC_SETUP_ERROR;
×
1115
  }
1116

1117
  SStdRes* pRes = GET_ROWCELL_INTERBUF(pResultInfo);
7,710,551✔
1118
  (void)memset(pRes, 0, sizeof(SStdRes));
7,710,551✔
1119
  return TSDB_CODE_SUCCESS;
7,710,551✔
1120
}
1121

1122
int32_t stdFunction(SqlFunctionCtx* pCtx) {
7,660,397✔
1123
  int32_t numOfElem = 0;
7,660,397✔
1124

1125
  // Only the pre-computing information loaded and actual data does not loaded
1126
  SInputColumnInfoData* pInput = &pCtx->input;
7,660,397✔
1127
  int32_t               type = pInput->pData[0]->info.type;
7,660,397✔
1128

1129
  SStdRes* pStdRes = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
7,660,397✔
1130
  pStdRes->type = type;
7,660,397✔
1131

1132
  // computing based on the true data block
1133
  SColumnInfoData* pCol = pInput->pData[0];
7,660,397✔
1134

1135
  int32_t start = pInput->startRowIndex;
7,660,397✔
1136
  int32_t numOfRows = pInput->numOfRows;
7,660,397✔
1137

1138
  if (IS_NULL_TYPE(type)) {
7,660,397✔
1139
    numOfElem = 0;
131✔
1140
    goto _stddev_over;
131✔
1141
  }
1142

1143
  switch (type) {
7,660,266!
1144
    case TSDB_DATA_TYPE_TINYINT: {
5,131,566✔
1145
      int8_t* plist = (int8_t*)pCol->pData;
5,131,566✔
1146
      for (int32_t i = start; i < numOfRows + start; ++i) {
18,731,443✔
1147
        if (pCol->hasNull && colDataIsNull_f(pCol->nullbitmap, i)) {
13,599,877✔
1148
          continue;
26,436✔
1149
        }
1150

1151
        numOfElem += 1;
13,573,441✔
1152
        pStdRes->count += 1;
13,573,441✔
1153
        pStdRes->isum += plist[i];
13,573,441✔
1154
        pStdRes->quadraticISum += plist[i] * plist[i];
13,573,441✔
1155
      }
1156

1157
      break;
5,131,566✔
1158
    }
1159

1160
    case TSDB_DATA_TYPE_SMALLINT: {
228,207✔
1161
      int16_t* plist = (int16_t*)pCol->pData;
228,207✔
1162
      for (int32_t i = start; i < numOfRows + pInput->startRowIndex; ++i) {
1,338,665✔
1163
        if (pCol->hasNull && colDataIsNull_f(pCol->nullbitmap, i)) {
1,110,458✔
1164
          continue;
44,028✔
1165
        }
1166

1167
        numOfElem += 1;
1,066,430✔
1168
        pStdRes->count += 1;
1,066,430✔
1169
        pStdRes->isum += plist[i];
1,066,430✔
1170
        pStdRes->quadraticISum += plist[i] * plist[i];
1,066,430✔
1171
      }
1172
      break;
228,207✔
1173
    }
1174

1175
    case TSDB_DATA_TYPE_INT: {
26,014✔
1176
      int32_t* plist = (int32_t*)pCol->pData;
26,014✔
1177
      for (int32_t i = start; i < numOfRows + pInput->startRowIndex; ++i) {
1,129,226✔
1178
        if (pCol->hasNull && colDataIsNull_f(pCol->nullbitmap, i)) {
1,103,212✔
1179
          continue;
167,201✔
1180
        }
1181

1182
        numOfElem += 1;
936,011✔
1183
        pStdRes->count += 1;
936,011✔
1184
        pStdRes->isum += plist[i];
936,011✔
1185
        pStdRes->quadraticISum += plist[i] * plist[i];
936,011✔
1186
      }
1187

1188
      break;
26,014✔
1189
    }
1190

1191
    case TSDB_DATA_TYPE_BIGINT: {
26,109✔
1192
      int64_t* plist = (int64_t*)pCol->pData;
26,109✔
1193
      for (int32_t i = start; i < numOfRows + pInput->startRowIndex; ++i) {
897,479✔
1194
        if (pCol->hasNull && colDataIsNull_f(pCol->nullbitmap, i)) {
871,370✔
1195
          continue;
34,304✔
1196
        }
1197

1198
        numOfElem += 1;
837,066✔
1199
        pStdRes->count += 1;
837,066✔
1200
        pStdRes->isum += plist[i];
837,066✔
1201
        pStdRes->quadraticISum += plist[i] * plist[i];
837,066✔
1202
      }
1203
      break;
26,109✔
1204
    }
1205

1206
    case TSDB_DATA_TYPE_UTINYINT: {
25✔
1207
      uint8_t* plist = (uint8_t*)pCol->pData;
25✔
1208
      for (int32_t i = start; i < numOfRows + start; ++i) {
80,032✔
1209
        if (pCol->hasNull && colDataIsNull_f(pCol->nullbitmap, i)) {
80,007!
1210
          continue;
4✔
1211
        }
1212

1213
        numOfElem += 1;
80,003✔
1214
        pStdRes->count += 1;
80,003✔
1215
        pStdRes->usum += plist[i];
80,003✔
1216
        pStdRes->quadraticUSum += plist[i] * plist[i];
80,003✔
1217
      }
1218

1219
      break;
25✔
1220
    }
1221

1222
    case TSDB_DATA_TYPE_USMALLINT: {
24✔
1223
      uint16_t* plist = (uint16_t*)pCol->pData;
24✔
1224
      for (int32_t i = start; i < numOfRows + pInput->startRowIndex; ++i) {
80,024✔
1225
        if (pCol->hasNull && colDataIsNull_f(pCol->nullbitmap, i)) {
80,000!
1226
          continue;
×
1227
        }
1228

1229
        numOfElem += 1;
80,000✔
1230
        pStdRes->count += 1;
80,000✔
1231
        pStdRes->usum += plist[i];
80,000✔
1232
        pStdRes->quadraticUSum += plist[i] * plist[i];
80,000✔
1233
      }
1234
      break;
24✔
1235
    }
1236

1237
    case TSDB_DATA_TYPE_UINT: {
25✔
1238
      uint32_t* plist = (uint32_t*)pCol->pData;
25✔
1239
      for (int32_t i = start; i < numOfRows + pInput->startRowIndex; ++i) {
80,030✔
1240
        if (pCol->hasNull && colDataIsNull_f(pCol->nullbitmap, i)) {
80,005!
1241
          continue;
×
1242
        }
1243

1244
        numOfElem += 1;
80,005✔
1245
        pStdRes->count += 1;
80,005✔
1246
        pStdRes->usum += plist[i];
80,005✔
1247
        pStdRes->quadraticUSum += plist[i] * plist[i];
80,005✔
1248
      }
1249

1250
      break;
25✔
1251
    }
1252

1253
    case TSDB_DATA_TYPE_UBIGINT: {
24✔
1254
      uint64_t* plist = (uint64_t*)pCol->pData;
24✔
1255
      for (int32_t i = start; i < numOfRows + pInput->startRowIndex; ++i) {
80,024✔
1256
        if (pCol->hasNull && colDataIsNull_f(pCol->nullbitmap, i)) {
80,000!
1257
          continue;
×
1258
        }
1259

1260
        numOfElem += 1;
80,000✔
1261
        pStdRes->count += 1;
80,000✔
1262
        pStdRes->usum += plist[i];
80,000✔
1263
        pStdRes->quadraticUSum += plist[i] * plist[i];
80,000✔
1264
      }
1265
      break;
24✔
1266
    }
1267

1268
    case TSDB_DATA_TYPE_FLOAT: {
13,315✔
1269
      float* plist = (float*)pCol->pData;
13,315✔
1270
      for (int32_t i = start; i < numOfRows + pInput->startRowIndex; ++i) {
1,880,403✔
1271
        if (pCol->hasNull && colDataIsNull_f(pCol->nullbitmap, i)) {
1,867,088✔
1272
          continue;
17,109✔
1273
        }
1274

1275
        numOfElem += 1;
1,849,979✔
1276
        pStdRes->count += 1;
1,849,979✔
1277
        pStdRes->dsum += plist[i];
1,849,979✔
1278
        pStdRes->quadraticDSum += plist[i] * plist[i];
1,849,979✔
1279
      }
1280
      break;
13,315✔
1281
    }
1282

1283
    case TSDB_DATA_TYPE_DOUBLE: {
2,235,076✔
1284
      double* plist = (double*)pCol->pData;
2,235,076✔
1285
      for (int32_t i = start; i < numOfRows + pInput->startRowIndex; ++i) {
8,525,646✔
1286
        if (pCol->hasNull && colDataIsNull_f(pCol->nullbitmap, i)) {
6,290,570✔
1287
          continue;
523,028✔
1288
        }
1289

1290
        numOfElem += 1;
5,767,542✔
1291
        pStdRes->count += 1;
5,767,542✔
1292
        pStdRes->dsum += plist[i];
5,767,542✔
1293
        pStdRes->quadraticDSum += plist[i] * plist[i];
5,767,542✔
1294
      }
1295
      break;
2,235,076✔
1296
    }
1297

UNCOV
1298
    default:
×
UNCOV
1299
      break;
×
1300
  }
1301

1302
_stddev_over:
7,660,397✔
1303
  // data in the check operation are all null, not output
1304
  SET_VAL(GET_RES_INFO(pCtx), numOfElem, 1);
7,660,397✔
1305
  return TSDB_CODE_SUCCESS;
7,660,397✔
1306
}
1307

1308
static void stdTransferInfo(SStdRes* pInput, SStdRes* pOutput) {
986,957✔
1309
  if (IS_NULL_TYPE(pInput->type)) {
986,957✔
1310
    return;
80✔
1311
  }
1312
  pOutput->type = pInput->type;
986,877✔
1313
  if (IS_SIGNED_NUMERIC_TYPE(pOutput->type)) {
986,877!
1314
    pOutput->quadraticISum += pInput->quadraticISum;
984,611✔
1315
    pOutput->isum += pInput->isum;
984,611✔
1316
  } else if (IS_UNSIGNED_NUMERIC_TYPE(pOutput->type)) {
2,266!
1317
    pOutput->quadraticUSum += pInput->quadraticUSum;
1✔
1318
    pOutput->usum += pInput->usum;
1✔
1319
  } else {
1320
    pOutput->quadraticDSum += pInput->quadraticDSum;
2,265✔
1321
    pOutput->dsum += pInput->dsum;
2,265✔
1322
  }
1323

1324
  pOutput->count += pInput->count;
986,877✔
1325
}
1326

1327
int32_t stdFunctionMerge(SqlFunctionCtx* pCtx) {
986,884✔
1328
  SInputColumnInfoData* pInput = &pCtx->input;
986,884✔
1329
  SColumnInfoData*      pCol = pInput->pData[0];
986,884✔
1330

1331
  if (IS_NULL_TYPE(pCol->info.type)) {
986,884!
1332
    SET_VAL(GET_RES_INFO(pCtx), 0, 1);
×
1333
    return TSDB_CODE_SUCCESS;
×
1334
  }
1335

1336
  if (pCol->info.type != TSDB_DATA_TYPE_BINARY) {
986,884!
1337
    return TSDB_CODE_FUNC_FUNTION_PARA_TYPE;
×
1338
  }
1339

1340
  SStdRes* pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
986,884✔
1341

1342
  for (int32_t i = pInput->startRowIndex; i < pInput->startRowIndex + pInput->numOfRows; ++i) {
1,973,838✔
1343
    if (colDataIsNull_s(pCol, i)) continue;
1,973,908!
1344
    char*    data = colDataGetData(pCol, i);
986,954!
1345
    SStdRes* pInputInfo = (SStdRes*)varDataVal(data);
986,954✔
1346
    stdTransferInfo(pInputInfo, pInfo);
986,954✔
1347
  }
1348

1349
  SET_VAL(GET_RES_INFO(pCtx), 1, 1);
986,884✔
1350
  return TSDB_CODE_SUCCESS;
986,884✔
1351
}
1352

1353
#ifdef BUILD_NO_CALL
1354
int32_t stdInvertFunction(SqlFunctionCtx* pCtx) {
1355
  int32_t numOfElem = 0;
1356

1357
  // Only the pre-computing information loaded and actual data does not loaded
1358
  SInputColumnInfoData* pInput = &pCtx->input;
1359
  int32_t               type = pInput->pData[0]->info.type;
1360

1361
  SStdRes* pStdRes = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
1362

1363
  // computing based on the true data block
1364
  SColumnInfoData* pCol = pInput->pData[0];
1365

1366
  int32_t start = pInput->startRowIndex;
1367
  int32_t numOfRows = pInput->numOfRows;
1368

1369
  switch (type) {
1370
    case TSDB_DATA_TYPE_TINYINT: {
1371
      LIST_STDDEV_SUB_N(pStdRes->isum, int8_t);
1372
      break;
1373
    }
1374
    case TSDB_DATA_TYPE_SMALLINT: {
1375
      LIST_STDDEV_SUB_N(pStdRes->isum, int16_t);
1376
      break;
1377
    }
1378
    case TSDB_DATA_TYPE_INT: {
1379
      LIST_STDDEV_SUB_N(pStdRes->isum, int32_t);
1380
      break;
1381
    }
1382
    case TSDB_DATA_TYPE_BIGINT: {
1383
      LIST_STDDEV_SUB_N(pStdRes->isum, int64_t);
1384
      break;
1385
    }
1386
    case TSDB_DATA_TYPE_UTINYINT: {
1387
      LIST_STDDEV_SUB_N(pStdRes->isum, uint8_t);
1388
      break;
1389
    }
1390
    case TSDB_DATA_TYPE_USMALLINT: {
1391
      LIST_STDDEV_SUB_N(pStdRes->isum, uint16_t);
1392
      break;
1393
    }
1394
    case TSDB_DATA_TYPE_UINT: {
1395
      LIST_STDDEV_SUB_N(pStdRes->isum, uint32_t);
1396
      break;
1397
    }
1398
    case TSDB_DATA_TYPE_UBIGINT: {
1399
      LIST_STDDEV_SUB_N(pStdRes->isum, uint64_t);
1400
      break;
1401
    }
1402
    case TSDB_DATA_TYPE_FLOAT: {
1403
      LIST_STDDEV_SUB_N(pStdRes->dsum, float);
1404
      break;
1405
    }
1406
    case TSDB_DATA_TYPE_DOUBLE: {
1407
      LIST_STDDEV_SUB_N(pStdRes->dsum, double);
1408
      break;
1409
    }
1410
    default:
1411
      break;
1412
  }
1413

1414
  // data in the check operation are all null, not output
1415
  SET_VAL(GET_RES_INFO(pCtx), numOfElem, 1);
1416
  return TSDB_CODE_SUCCESS;
1417
}
1418
#endif
1419

1420
int32_t stddevFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
6,687,177✔
1421
  SInputColumnInfoData* pInput = &pCtx->input;
6,687,177✔
1422
  SStdRes*              pStddevRes = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
6,687,177✔
1423
  int32_t               type = pStddevRes->type;
6,687,177✔
1424
  double                avg;
1425

1426
  if (pStddevRes->count == 0) {
6,687,177✔
1427
    GET_RES_INFO(pCtx)->numOfRes = 0;
45,869✔
1428
    return functionFinalize(pCtx, pBlock);
45,869✔
1429
  }
1430

1431
  if (IS_SIGNED_NUMERIC_TYPE(type)) {
6,641,308!
1432
    avg = pStddevRes->isum / ((double)pStddevRes->count);
4,421,624✔
1433
    pStddevRes->result = sqrt(fabs(pStddevRes->quadraticISum / ((double)pStddevRes->count) - avg * avg));
4,421,624✔
1434
  } else if (IS_UNSIGNED_NUMERIC_TYPE(type)) {
2,219,684!
1435
    avg = pStddevRes->usum / ((double)pStddevRes->count);
10✔
1436
    pStddevRes->result = sqrt(fabs(pStddevRes->quadraticUSum / ((double)pStddevRes->count) - avg * avg));
10✔
1437
  } else {
1438
    avg = pStddevRes->dsum / ((double)pStddevRes->count);
2,219,674✔
1439
    pStddevRes->result = sqrt(fabs(pStddevRes->quadraticDSum / ((double)pStddevRes->count) - avg * avg));
2,219,674✔
1440
  }
1441

1442
  // check for overflow
1443
  if (isinf(pStddevRes->result) || isnan(pStddevRes->result)) {
6,641,308!
1444
    GET_RES_INFO(pCtx)->numOfRes = 0;
×
1445
  }
1446

1447
  return functionFinalize(pCtx, pBlock);
6,641,308✔
1448
}
1449

1450
int32_t stdvarFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
×
1451
  SInputColumnInfoData* pInput = &pCtx->input;
×
1452
  SStdRes*              pStdvarRes = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
×
1453
  int32_t               type = pStdvarRes->type;
×
1454
  double                avg;
1455

1456
  if (pStdvarRes->count == 0) {
×
1457
    GET_RES_INFO(pCtx)->numOfRes = 0;
×
1458
    return functionFinalize(pCtx, pBlock);
×
1459
  }
1460

1461
  if (IS_SIGNED_NUMERIC_TYPE(type)) {
×
1462
    avg = pStdvarRes->isum / ((double)pStdvarRes->count);
×
1463
    pStdvarRes->result = fabs(pStdvarRes->quadraticISum / ((double)pStdvarRes->count) - avg * avg);
×
1464
  } else if (IS_UNSIGNED_NUMERIC_TYPE(type)) {
×
1465
    avg = pStdvarRes->usum / ((double)pStdvarRes->count);
×
1466
    pStdvarRes->result = fabs(pStdvarRes->quadraticUSum / ((double)pStdvarRes->count) - avg * avg);
×
1467
  } else {
1468
    avg = pStdvarRes->dsum / ((double)pStdvarRes->count);
×
1469
    pStdvarRes->result = fabs(pStdvarRes->quadraticDSum / ((double)pStdvarRes->count) - avg * avg);
×
1470
  }
1471

1472
  // check for overflow
1473
  if (isinf(pStdvarRes->result) || isnan(pStdvarRes->result)) {
×
1474
    GET_RES_INFO(pCtx)->numOfRes = 0;
×
1475
  }
1476

1477
  return functionFinalize(pCtx, pBlock);
×
1478
}
1479

1480
int32_t stdPartialFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
986,872✔
1481
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
986,872✔
1482
  SStdRes*             pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
986,872✔
1483
  int32_t              resultBytes = getStdInfoSize();
986,872✔
1484
  char*                res = taosMemoryCalloc(resultBytes + VARSTR_HEADER_SIZE, sizeof(char));
986,871!
1485

1486
  if (NULL == res) {
986,872!
1487
    return terrno;
×
1488
  }
1489
  (void)memcpy(varDataVal(res), pInfo, resultBytes);
986,872✔
1490
  varDataSetLen(res, resultBytes);
986,872✔
1491

1492
  int32_t          slotId = pCtx->pExpr->base.resSchema.slotId;
986,872✔
1493
  SColumnInfoData* pCol = taosArrayGet(pBlock->pDataBlock, slotId);
986,872✔
1494
  if (NULL == pCol) {
986,871!
1495
    taosMemoryFree(res);
×
1496
    return TSDB_CODE_OUT_OF_RANGE;
×
1497
  }
1498

1499
  int32_t code = colDataSetVal(pCol, pBlock->info.rows, res, false);
986,871✔
1500

1501
  taosMemoryFree(res);
986,870!
1502
  return code;
986,872✔
1503
}
1504

1505
int32_t stdCombine(SqlFunctionCtx* pDestCtx, SqlFunctionCtx* pSourceCtx) {
3✔
1506
  SResultRowEntryInfo* pDResInfo = GET_RES_INFO(pDestCtx);
3✔
1507
  SStdRes*             pDBuf = GET_ROWCELL_INTERBUF(pDResInfo);
3✔
1508

1509
  SResultRowEntryInfo* pSResInfo = GET_RES_INFO(pSourceCtx);
3✔
1510
  SStdRes*             pSBuf = GET_ROWCELL_INTERBUF(pSResInfo);
3✔
1511
  int16_t              type = pDBuf->type == TSDB_DATA_TYPE_NULL ? pSBuf->type : pDBuf->type;
3!
1512

1513
  stdTransferInfo(pSBuf, pDBuf);
3✔
1514

1515
  pDResInfo->numOfRes = TMAX(pDResInfo->numOfRes, pSResInfo->numOfRes);
3✔
1516
  pDResInfo->isNullRes &= pSResInfo->isNullRes;
3✔
1517
  return TSDB_CODE_SUCCESS;
3✔
1518
}
1519

1520
bool getLeastSQRFuncEnv(SFunctionNode* pFunc, SFuncExecEnv* pEnv) {
44,355✔
1521
  pEnv->calcMemSize = sizeof(SLeastSQRInfo);
44,355✔
1522
  return true;
44,355✔
1523
}
1524

1525
int32_t leastSQRFunctionSetup(SqlFunctionCtx* pCtx, SResultRowEntryInfo* pResultInfo) {
4,041,661✔
1526
  if (pResultInfo->initialized) {
4,041,661!
1527
    return TSDB_CODE_SUCCESS;
×
1528
  }
1529
  if (TSDB_CODE_SUCCESS != functionSetup(pCtx, pResultInfo)) {
4,041,661!
1530
    return TSDB_CODE_FUNC_SETUP_ERROR;
×
1531
  }
1532

1533
  SLeastSQRInfo* pInfo = GET_ROWCELL_INTERBUF(pResultInfo);
4,041,664✔
1534

1535
  GET_TYPED_DATA(pInfo->startVal, double, pCtx->param[1].param.nType, &pCtx->param[1].param.i);
4,041,664!
1536
  GET_TYPED_DATA(pInfo->stepVal, double, pCtx->param[2].param.nType, &pCtx->param[2].param.i);
4,041,664!
1537
  return TSDB_CODE_SUCCESS;
4,041,664✔
1538
}
1539

1540
int32_t leastSQRFunction(SqlFunctionCtx* pCtx) {
4,083,001✔
1541
  int32_t numOfElem = 0;
4,083,001✔
1542

1543
  SInputColumnInfoData* pInput = &pCtx->input;
4,083,001✔
1544
  int32_t               type = pInput->pData[0]->info.type;
4,083,001✔
1545

1546
  SLeastSQRInfo* pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
4,083,001✔
1547

1548
  SColumnInfoData* pCol = pInput->pData[0];
4,083,001✔
1549

1550
  double(*param)[3] = pInfo->matrix;
4,083,001✔
1551
  double x = pInfo->startVal;
4,083,001✔
1552

1553
  int32_t start = pInput->startRowIndex;
4,083,001✔
1554
  int32_t numOfRows = pInput->numOfRows;
4,083,001✔
1555

1556
  switch (type) {
4,083,001!
1557
    case TSDB_DATA_TYPE_TINYINT: {
12,761✔
1558
      int8_t* plist = (int8_t*)pCol->pData;
12,761✔
1559
      for (int32_t i = start; i < numOfRows + pInput->startRowIndex; ++i) {
391,312✔
1560
        if (pCol->hasNull && colDataIsNull_f(pCol->nullbitmap, i)) {
378,551✔
1561
          continue;
1,636✔
1562
        }
1563
        numOfElem++;
376,915✔
1564
        LEASTSQR_CAL(param, x, plist, i, pInfo->stepVal);
376,915✔
1565
      }
1566
      break;
12,761✔
1567
    }
1568
    case TSDB_DATA_TYPE_SMALLINT: {
7,194✔
1569
      int16_t* plist = (int16_t*)pCol->pData;
7,194✔
1570
      for (int32_t i = start; i < numOfRows + pInput->startRowIndex; ++i) {
292,778✔
1571
        if (pCol->hasNull && colDataIsNull_f(pCol->nullbitmap, i)) {
285,584✔
1572
          continue;
1,836✔
1573
        }
1574

1575
        numOfElem++;
283,748✔
1576
        LEASTSQR_CAL(param, x, plist, i, pInfo->stepVal);
283,748✔
1577
      }
1578
      break;
7,194✔
1579
    }
1580

1581
    case TSDB_DATA_TYPE_INT: {
4,037,172✔
1582
      int32_t* plist = (int32_t*)pCol->pData;
4,037,172✔
1583
      for (int32_t i = start; i < numOfRows + pInput->startRowIndex; ++i) {
13,195,947✔
1584
        if (pCol->hasNull && colDataIsNull_f(pCol->nullbitmap, i)) {
9,158,775✔
1585
          continue;
275,133✔
1586
        }
1587

1588
        numOfElem++;
8,883,642✔
1589
        LEASTSQR_CAL(param, x, plist, i, pInfo->stepVal);
8,883,642✔
1590
      }
1591
      break;
4,037,172✔
1592
    }
1593

1594
    case TSDB_DATA_TYPE_BIGINT: {
8,797✔
1595
      int64_t* plist = (int64_t*)pCol->pData;
8,797✔
1596
      for (int32_t i = start; i < numOfRows + pInput->startRowIndex; ++i) {
491,965✔
1597
        if (pCol->hasNull && colDataIsNull_f(pCol->nullbitmap, i)) {
483,168✔
1598
          continue;
2,436✔
1599
        }
1600

1601
        numOfElem++;
480,732✔
1602
        LEASTSQR_CAL(param, x, plist, i, pInfo->stepVal);
480,732✔
1603
      }
1604
      break;
8,797✔
1605
    }
1606

1607
    case TSDB_DATA_TYPE_UTINYINT: {
102✔
1608
      uint8_t* plist = (uint8_t*)pCol->pData;
102✔
1609
      for (int32_t i = start; i < numOfRows + pInput->startRowIndex; ++i) {
80,354✔
1610
        if (pCol->hasNull && colDataIsNull_f(pCol->nullbitmap, i)) {
80,252!
1611
          continue;
66✔
1612
        }
1613
        numOfElem++;
80,186✔
1614
        LEASTSQR_CAL(param, x, plist, i, pInfo->stepVal);
80,186✔
1615
      }
1616
      break;
102✔
1617
    }
1618
    case TSDB_DATA_TYPE_USMALLINT: {
102✔
1619
      uint16_t* plist = (uint16_t*)pCol->pData;
102✔
1620
      for (int32_t i = start; i < numOfRows + pInput->startRowIndex; ++i) {
80,354✔
1621
        if (pCol->hasNull && colDataIsNull_f(pCol->nullbitmap, i)) {
80,252!
1622
          continue;
60✔
1623
        }
1624

1625
        numOfElem++;
80,192✔
1626
        LEASTSQR_CAL(param, x, plist, i, pInfo->stepVal);
80,192✔
1627
      }
1628
      break;
102✔
1629
    }
1630

1631
    case TSDB_DATA_TYPE_UINT: {
102✔
1632
      uint32_t* plist = (uint32_t*)pCol->pData;
102✔
1633
      for (int32_t i = start; i < numOfRows + pInput->startRowIndex; ++i) {
80,354✔
1634
        if (pCol->hasNull && colDataIsNull_f(pCol->nullbitmap, i)) {
80,252!
1635
          continue;
60✔
1636
        }
1637

1638
        numOfElem++;
80,192✔
1639
        LEASTSQR_CAL(param, x, plist, i, pInfo->stepVal);
80,192✔
1640
      }
1641
      break;
102✔
1642
    }
1643

1644
    case TSDB_DATA_TYPE_UBIGINT: {
102✔
1645
      uint64_t* plist = (uint64_t*)pCol->pData;
102✔
1646
      for (int32_t i = start; i < numOfRows + pInput->startRowIndex; ++i) {
80,354✔
1647
        if (pCol->hasNull && colDataIsNull_f(pCol->nullbitmap, i)) {
80,252!
1648
          continue;
60✔
1649
        }
1650

1651
        numOfElem++;
80,192✔
1652
        LEASTSQR_CAL(param, x, plist, i, pInfo->stepVal);
80,192✔
1653
      }
1654
      break;
102✔
1655
    }
1656

1657
    case TSDB_DATA_TYPE_FLOAT: {
7,554✔
1658
      float* plist = (float*)pCol->pData;
7,554✔
1659
      for (int32_t i = start; i < numOfRows + pInput->startRowIndex; ++i) {
284,170✔
1660
        if (pCol->hasNull && colDataIsNull_f(pCol->nullbitmap, i)) {
276,616✔
1661
          continue;
4,036✔
1662
        }
1663

1664
        numOfElem++;
272,580✔
1665
        LEASTSQR_CAL(param, x, plist, i, pInfo->stepVal);
272,580✔
1666
      }
1667
      break;
7,554✔
1668
    }
1669

1670
    case TSDB_DATA_TYPE_DOUBLE: {
9,115✔
1671
      double* plist = (double*)pCol->pData;
9,115✔
1672
      for (int32_t i = start; i < numOfRows + pInput->startRowIndex; ++i) {
244,563✔
1673
        if (pCol->hasNull && colDataIsNull_f(pCol->nullbitmap, i)) {
235,448✔
1674
          continue;
149,068✔
1675
        }
1676

1677
        numOfElem++;
86,380✔
1678
        LEASTSQR_CAL(param, x, plist, i, pInfo->stepVal);
86,380✔
1679
      }
1680
      break;
9,115✔
1681
    }
1682
    case TSDB_DATA_TYPE_NULL: {
×
1683
      GET_RES_INFO(pCtx)->isNullRes = 1;
×
1684
      numOfElem = 1;
×
1685
      break;
×
1686
    }
1687

1688
    default:
×
1689
      break;
×
1690
  }
1691

1692
  pInfo->startVal = x;
4,083,001✔
1693
  pInfo->num += numOfElem;
4,083,001✔
1694

1695
  SET_VAL(GET_RES_INFO(pCtx), numOfElem, 1);
4,083,001✔
1696

1697
  return TSDB_CODE_SUCCESS;
4,083,001✔
1698
}
1699

1700
int32_t leastSQRFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
4,027,768✔
1701
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
4,027,768✔
1702
  SLeastSQRInfo*       pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
4,027,768✔
1703
  int32_t              slotId = pCtx->pExpr->base.resSchema.slotId;
4,027,768✔
1704
  SColumnInfoData*     pCol = taosArrayGet(pBlock->pDataBlock, slotId);
4,027,768✔
1705

1706
  if (NULL == pCol) {
4,027,766!
1707
    return TSDB_CODE_OUT_OF_RANGE;
×
1708
  }
1709
  int32_t currentRow = pBlock->info.rows;
4,027,766✔
1710

1711
  if (0 == pInfo->num) {
4,027,766✔
1712
    colDataSetNULL(pCol, currentRow);
17,200!
1713
    return TSDB_CODE_SUCCESS;
17,200✔
1714
  }
1715

1716
  double(*param)[3] = pInfo->matrix;
4,010,566✔
1717

1718
  param[1][1] = (double)pInfo->num;
4,010,566✔
1719
  param[1][0] = param[0][1];
4,010,566✔
1720

1721
  double param00 = param[0][0] - param[1][0] * (param[0][1] / param[1][1]);
4,010,566✔
1722
  double param02 = param[0][2] - param[1][2] * (param[0][1] / param[1][1]);
4,010,566✔
1723

1724
  if (0 == param00) {
4,010,566✔
1725
    colDataSetNULL(pCol, currentRow);
3,645,758!
1726
    return TSDB_CODE_SUCCESS;
3,645,758✔
1727
  }
1728

1729
  // param[0][1] = 0;
1730
  double param12 = param[1][2] - param02 * (param[1][0] / param00);
364,808✔
1731
  // param[1][0] = 0;
1732
  param02 /= param00;
364,808✔
1733

1734
  param12 /= param[1][1];
364,808✔
1735

1736
  char buf[LEASTSQUARES_BUFF_LENGTH] = {0};
364,808✔
1737
  char slopBuf[64] = {0};
364,808✔
1738
  char interceptBuf[64] = {0};
364,808✔
1739
  int  n = tsnprintf(slopBuf, 64, "%.6lf", param02);
364,808✔
1740
  if (n > LEASTSQUARES_DOUBLE_ITEM_LENGTH) {
364,813✔
1741
    (void)snprintf(slopBuf, 64, "%." DOUBLE_PRECISION_DIGITS, param02);
76✔
1742
  }
1743
  n = tsnprintf(interceptBuf, 64, "%.6lf", param12);
364,813✔
1744
  if (n > LEASTSQUARES_DOUBLE_ITEM_LENGTH) {
364,814✔
1745
    (void)snprintf(interceptBuf, 64, "%." DOUBLE_PRECISION_DIGITS, param12);
1,912✔
1746
  }
1747
  size_t len =
364,814✔
1748
      snprintf(varDataVal(buf), sizeof(buf) - VARSTR_HEADER_SIZE, "{slop:%s, intercept:%s}", slopBuf, interceptBuf);
364,814✔
1749
  varDataSetLen(buf, len);
364,814✔
1750

1751
  int32_t code = colDataSetVal(pCol, currentRow, buf, pResInfo->isNullRes);
364,814✔
1752

1753
  return code;
364,814✔
1754
}
1755

1756
int32_t leastSQRCombine(SqlFunctionCtx* pDestCtx, SqlFunctionCtx* pSourceCtx) {
×
1757
  SResultRowEntryInfo* pDResInfo = GET_RES_INFO(pDestCtx);
×
1758
  SLeastSQRInfo*       pDBuf = GET_ROWCELL_INTERBUF(pDResInfo);
×
1759
  int32_t              type = pDestCtx->input.pData[0]->info.type;
×
1760
  double(*pDparam)[3] = pDBuf->matrix;
×
1761

1762
  SResultRowEntryInfo* pSResInfo = GET_RES_INFO(pSourceCtx);
×
1763
  SLeastSQRInfo*       pSBuf = GET_ROWCELL_INTERBUF(pSResInfo);
×
1764
  double(*pSparam)[3] = pSBuf->matrix;
×
1765
  for (int32_t i = 0; i < pSBuf->num; i++) {
×
1766
    pDparam[0][0] += pDBuf->startVal * pDBuf->startVal;
×
1767
    pDparam[0][1] += pDBuf->startVal;
×
1768
    pDBuf->startVal += pDBuf->stepVal;
×
1769
  }
1770
  pDparam[0][2] += pSparam[0][2] + pDBuf->num * pDBuf->stepVal * pSparam[1][2];
×
1771
  pDparam[1][2] += pSparam[1][2];
×
1772
  pDBuf->num += pSBuf->num;
×
1773
  pDResInfo->numOfRes = TMAX(pDResInfo->numOfRes, pSResInfo->numOfRes);
×
1774
  pDResInfo->isNullRes &= pSResInfo->isNullRes;
×
1775
  return TSDB_CODE_SUCCESS;
×
1776
}
1777

1778
bool getPercentileFuncEnv(SFunctionNode* pFunc, SFuncExecEnv* pEnv) {
939✔
1779
  pEnv->calcMemSize = sizeof(SPercentileInfo);
939✔
1780
  return true;
939✔
1781
}
1782

1783
int32_t percentileFunctionSetup(SqlFunctionCtx* pCtx, SResultRowEntryInfo* pResultInfo) {
5,937✔
1784
  if (pResultInfo->initialized) {
5,937!
1785
    return TSDB_CODE_SUCCESS;
×
1786
  }
1787
  if (TSDB_CODE_SUCCESS != functionSetup(pCtx, pResultInfo)) {
5,937!
1788
    return TSDB_CODE_FUNC_SETUP_ERROR;
×
1789
  }
1790

1791
  // in the first round, get the min-max value of all involved data
1792
  SPercentileInfo* pInfo = GET_ROWCELL_INTERBUF(pResultInfo);
5,937✔
1793
  SET_DOUBLE_VAL(&pInfo->minval, DBL_MAX);
5,937✔
1794
  SET_DOUBLE_VAL(&pInfo->maxval, -DBL_MAX);
5,937✔
1795
  pInfo->numOfElems = 0;
5,937✔
1796

1797
  return TSDB_CODE_SUCCESS;
5,937✔
1798
}
1799

1800
void percentileFunctionCleanupExt(SqlFunctionCtx* pCtx) {
×
1801
  if (pCtx == NULL || GET_RES_INFO(pCtx) == NULL || GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx)) == NULL) {
×
1802
    return;
×
1803
  }
1804
  SPercentileInfo* pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
×
1805
  if (pInfo->pMemBucket != NULL) {
×
1806
    tMemBucketDestroy(&(pInfo->pMemBucket));
×
1807
    pInfo->pMemBucket = NULL;
×
1808
  }
1809
}
1810

1811
int32_t percentileFunction(SqlFunctionCtx* pCtx) {
2,694,226✔
1812
  int32_t              code = TSDB_CODE_SUCCESS;
2,694,226✔
1813
  int32_t              numOfElems = 0;
2,694,226✔
1814
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
2,694,226✔
1815

1816
  SInputColumnInfoData* pInput = &pCtx->input;
2,694,226✔
1817
  SColumnDataAgg*       pAgg = pInput->pColumnDataAgg[0];
2,694,226✔
1818

1819
  SColumnInfoData* pCol = pInput->pData[0];
2,694,226✔
1820
  int32_t          type = pCol->info.type;
2,694,226✔
1821

1822
  SPercentileInfo* pInfo = GET_ROWCELL_INTERBUF(pResInfo);
2,694,226✔
1823
  if (pCtx->scanFlag == MAIN_SCAN && pInfo->stage == 0) {
2,694,226✔
1824
    pInfo->stage += 1;
5,937✔
1825

1826
    // all data are null, set it completed
1827
    if (pInfo->numOfElems == 0) {
5,937✔
1828
      pResInfo->complete = true;
1,804✔
1829
      return TSDB_CODE_SUCCESS;
1,804✔
1830
    } else {
1831
      code = tMemBucketCreate(pCol->info.bytes, type, pInfo->minval, pInfo->maxval, pCtx->hasWindowOrGroup,
4,133✔
1832
                              &pInfo->pMemBucket, pInfo->numOfElems);
4,133✔
1833
      if (TSDB_CODE_SUCCESS != code) {
4,133!
1834
        return code;
×
1835
      }
1836
    }
1837
  }
1838

1839
  // the first stage, only acquire the min/max value
1840
  if (pInfo->stage == 0) {
2,692,422✔
1841
    if (pCtx->input.colDataSMAIsSet) {
1,347,113✔
1842
      double tmin = 0.0, tmax = 0.0;
1,337,994✔
1843
      if (IS_SIGNED_NUMERIC_TYPE(type)) {
1,337,994!
1844
        tmin = (double)GET_INT64_VAL(&pAgg->min);
×
1845
        tmax = (double)GET_INT64_VAL(&pAgg->max);
×
1846
      } else if (IS_FLOAT_TYPE(type)) {
1,337,994!
1847
        tmin = GET_DOUBLE_VAL(&pAgg->min);
1,337,994✔
1848
        tmax = GET_DOUBLE_VAL(&pAgg->max);
1,337,994✔
1849
      } else if (IS_UNSIGNED_NUMERIC_TYPE(type)) {
×
1850
        tmin = (double)GET_UINT64_VAL(&pAgg->min);
×
1851
        tmax = (double)GET_UINT64_VAL(&pAgg->max);
×
1852
      }
1853

1854
      if (GET_DOUBLE_VAL(&pInfo->minval) > tmin) {
1,337,994✔
1855
        SET_DOUBLE_VAL(&pInfo->minval, tmin);
14✔
1856
      }
1857

1858
      if (GET_DOUBLE_VAL(&pInfo->maxval) < tmax) {
1,337,994✔
1859
        SET_DOUBLE_VAL(&pInfo->maxval, tmax);
14✔
1860
      }
1861

1862
      pInfo->numOfElems += (pInput->numOfRows - pAgg->numOfNull);
1,337,994✔
1863
    } else {
1864
      // check the valid data one by one
1865
      int32_t start = pInput->startRowIndex;
9,119✔
1866
      for (int32_t i = start; i < pInput->numOfRows + start; ++i) {
9,274,142✔
1867
        if (colDataIsNull_f(pCol->nullbitmap, i)) {
9,265,023✔
1868
          continue;
2,200✔
1869
        }
1870

1871
        char* data = colDataGetData(pCol, i);
9,262,823!
1872

1873
        double v = 0;
9,262,823✔
1874
        GET_TYPED_DATA(v, double, type, data);
9,262,823!
1875
        if (v < GET_DOUBLE_VAL(&pInfo->minval)) {
9,262,823✔
1876
          SET_DOUBLE_VAL(&pInfo->minval, v);
4,371✔
1877
        }
1878

1879
        if (v > GET_DOUBLE_VAL(&pInfo->maxval)) {
9,262,823✔
1880
          SET_DOUBLE_VAL(&pInfo->maxval, v);
411,407✔
1881
        }
1882

1883
        pInfo->numOfElems += 1;
9,262,823✔
1884
      }
1885
    }
1886
  } else {
1887
    // the second stage, calculate the true percentile value
1888
    int32_t start = pInput->startRowIndex;
1,345,309✔
1889
    for (int32_t i = start; i < pInput->numOfRows + start; ++i) {
2,147,483,647✔
1890
      if (colDataIsNull_f(pCol->nullbitmap, i)) {
2,147,483,647!
1891
        continue;
×
1892
      }
1893

1894
      char* data = colDataGetData(pCol, i);
2,147,483,647!
1895
      numOfElems += 1;
2,147,483,647✔
1896
      code = tMemBucketPut(pInfo->pMemBucket, data, 1);
2,147,483,647✔
1897
      if (code != TSDB_CODE_SUCCESS) {
2,147,483,647!
1898
        tMemBucketDestroy(&(pInfo->pMemBucket));
×
1899
        return code;
×
1900
      }
1901
    }
1902

1903
    SET_VAL(pResInfo, numOfElems, 1);
1,345,309!
1904
  }
1905

1906
  pCtx->needCleanup = true;
2,692,422✔
1907
  return TSDB_CODE_SUCCESS;
2,692,422✔
1908
}
1909

1910
int32_t percentileFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
5,937✔
1911
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
5,937✔
1912
  SPercentileInfo*     ppInfo = (SPercentileInfo*)GET_ROWCELL_INTERBUF(pResInfo);
5,937✔
1913

1914
  int32_t code = 0;
5,937✔
1915
  double  v = 0;
5,937✔
1916

1917
  tMemBucket** pMemBucket = &ppInfo->pMemBucket;
5,937✔
1918
  if ((*pMemBucket) != NULL && (*pMemBucket)->total > 0) {  // check for null
5,937!
1919
    if (pCtx->numOfParams > 2) {
4,133✔
1920
      char buf[3200] = {0};
34✔
1921
      // max length of double num is 317, e.g. use %.6lf to print -1.0e+308, consider the comma and bracket, 3200 is
1922
      // enough.
1923
      size_t len = 1;
34✔
1924

1925
      varDataVal(buf)[0] = '[';
34✔
1926
      for (int32_t i = 1; i < pCtx->numOfParams; ++i) {
342✔
1927
        SVariant* pVal = &pCtx->param[i].param;
308✔
1928

1929
        GET_TYPED_DATA(v, double, pVal->nType, &pVal->i);
308!
1930

1931
        code = getPercentile((*pMemBucket), v, &ppInfo->result);
308✔
1932
        if (code != TSDB_CODE_SUCCESS) {
308!
1933
          goto _fin_error;
×
1934
        }
1935

1936
        if (i == pCtx->numOfParams - 1) {
308✔
1937
          len += tsnprintf(varDataVal(buf) + len, sizeof(buf) - VARSTR_HEADER_SIZE - len, "%.6lf]", ppInfo->result);
34✔
1938
        } else {
1939
          len += tsnprintf(varDataVal(buf) + len, sizeof(buf) - VARSTR_HEADER_SIZE - len, "%.6lf, ", ppInfo->result);
274✔
1940
        }
1941
      }
1942

1943
      int32_t          slotId = pCtx->pExpr->base.resSchema.slotId;
34✔
1944
      SColumnInfoData* pCol = taosArrayGet(pBlock->pDataBlock, slotId);
34✔
1945
      if (NULL == pCol) {
34!
1946
        code = terrno;
×
1947
        goto _fin_error;
×
1948
      }
1949

1950
      varDataSetLen(buf, len);
34✔
1951
      code = colDataSetVal(pCol, pBlock->info.rows, buf, false);
34✔
1952
      if (code != TSDB_CODE_SUCCESS) {
34!
1953
        goto _fin_error;
×
1954
      }
1955

1956
      tMemBucketDestroy(pMemBucket);
34✔
1957
      return TSDB_CODE_SUCCESS;
34✔
1958
    } else {
1959
      SVariant* pVal = &pCtx->param[1].param;
4,099✔
1960

1961
      GET_TYPED_DATA(v, double, pVal->nType, &pVal->i);
4,099!
1962

1963
      code = getPercentile((*pMemBucket), v, &ppInfo->result);
4,099✔
1964
      if (code != TSDB_CODE_SUCCESS) {
4,099!
1965
        goto _fin_error;
×
1966
      }
1967

1968
      tMemBucketDestroy(pMemBucket);
4,099✔
1969
      return functionFinalize(pCtx, pBlock);
4,099✔
1970
    }
1971
  } else {
1972
    return functionFinalize(pCtx, pBlock);
1,804✔
1973
  }
1974

1975
_fin_error:
×
1976

1977
  tMemBucketDestroy(pMemBucket);
×
1978
  return code;
×
1979
}
1980

1981
bool getApercentileFuncEnv(SFunctionNode* pFunc, SFuncExecEnv* pEnv) {
125,775✔
1982
  int32_t bytesHist =
125,775✔
1983
      (int32_t)(sizeof(SAPercentileInfo) + sizeof(SHistogramInfo) + sizeof(SHistBin) * (MAX_HISTOGRAM_BIN + 1));
1984
  int32_t bytesDigest = (int32_t)(sizeof(SAPercentileInfo) + TDIGEST_SIZE(COMPRESSION));
125,775✔
1985
  pEnv->calcMemSize = TMAX(bytesHist, bytesDigest);
125,775✔
1986
  return true;
125,775✔
1987
}
1988

1989
int32_t getApercentileMaxSize() {
1,900,701✔
1990
  int32_t bytesHist =
1,900,701✔
1991
      (int32_t)(sizeof(SAPercentileInfo) + sizeof(SHistogramInfo) + sizeof(SHistBin) * (MAX_HISTOGRAM_BIN + 1));
1992
  int32_t bytesDigest = (int32_t)(sizeof(SAPercentileInfo) + TDIGEST_SIZE(COMPRESSION));
1,900,701✔
1993
  return TMAX(bytesHist, bytesDigest);
1,900,701✔
1994
}
1995

1996
static int8_t getApercentileAlgo(char* algoStr) {
24,070✔
1997
  int8_t algoType;
1998
  if (strcasecmp(algoStr, "default") == 0) {
24,070✔
1999
    algoType = APERCT_ALGO_DEFAULT;
11,150✔
2000
  } else if (strcasecmp(algoStr, "t-digest") == 0) {
12,920✔
2001
    algoType = APERCT_ALGO_TDIGEST;
12,917✔
2002
  } else {
2003
    algoType = APERCT_ALGO_UNKNOWN;
3✔
2004
  }
2005

2006
  return algoType;
24,070✔
2007
}
2008

2009
static void buildHistogramInfo(SAPercentileInfo* pInfo) {
46,583,315✔
2010
  pInfo->pHisto = (SHistogramInfo*)((char*)pInfo + sizeof(SAPercentileInfo));
46,583,315✔
2011
  pInfo->pHisto->elems = (SHistBin*)((char*)pInfo->pHisto + sizeof(SHistogramInfo));
46,583,315✔
2012
}
46,583,315✔
2013

2014
static void buildTDigestInfo(SAPercentileInfo* pInfo) {
30,327✔
2015
  pInfo->pTDigest = (TDigest*)((char*)pInfo + sizeof(SAPercentileInfo));
30,327✔
2016
}
30,327✔
2017

2018
int32_t apercentileFunctionSetup(SqlFunctionCtx* pCtx, SResultRowEntryInfo* pResultInfo) {
14,868,199✔
2019
  if (pResultInfo->initialized) {
14,868,199!
2020
    return TSDB_CODE_SUCCESS;
×
2021
  }
2022
  if (TSDB_CODE_SUCCESS != functionSetup(pCtx, pResultInfo)) {
14,868,199!
2023
    return TSDB_CODE_FUNC_SETUP_ERROR;
×
2024
  }
2025

2026
  SAPercentileInfo* pInfo = GET_ROWCELL_INTERBUF(pResultInfo);
14,868,249✔
2027

2028
  SVariant* pVal = &pCtx->param[1].param;
14,868,249✔
2029
  pInfo->percent = 0;
14,868,249✔
2030
  GET_TYPED_DATA(pInfo->percent, double, pVal->nType, &pVal->i);
14,868,249!
2031

2032
  if (pCtx->numOfParams == 2) {
14,868,249✔
2033
    pInfo->algo = APERCT_ALGO_DEFAULT;
14,844,177✔
2034
  } else if (pCtx->numOfParams == 3) {
24,072✔
2035
    pInfo->algo = getApercentileAlgo(varDataVal(pCtx->param[2].param.pz));
24,070✔
2036
    if (pInfo->algo == APERCT_ALGO_UNKNOWN) {
24,060!
2037
      return TSDB_CODE_FUNC_FUNTION_PARA_VALUE;
×
2038
    }
2039
  }
2040

2041
  char* tmp = (char*)pInfo + sizeof(SAPercentileInfo);
14,868,239✔
2042
  if (pInfo->algo == APERCT_ALGO_TDIGEST) {
14,868,239✔
2043
    pInfo->pTDigest = tdigestNewFrom(tmp, COMPRESSION);
12,913✔
2044
  } else {
2045
    buildHistogramInfo(pInfo);
14,855,326✔
2046
    pInfo->pHisto = tHistogramCreateFrom(tmp, MAX_HISTOGRAM_BIN);
14,855,327✔
2047
    qDebug("%s set up histogram, numOfElems:%" PRId64 ", numOfEntry:%d, pHisto:%p, elems:%p", __FUNCTION__,
14,855,319✔
2048
           pInfo->pHisto->numOfElems, pInfo->pHisto->numOfEntries, pInfo->pHisto, pInfo->pHisto->elems);
2049
  }
2050

2051
  return TSDB_CODE_SUCCESS;
14,868,237✔
2052
}
2053

2054
int32_t apercentileFunction(SqlFunctionCtx* pCtx) {
13,122,467✔
2055
  int32_t               numOfElems = 0;
13,122,467✔
2056
  SResultRowEntryInfo*  pResInfo = GET_RES_INFO(pCtx);
13,122,467✔
2057
  SInputColumnInfoData* pInput = &pCtx->input;
13,122,467✔
2058

2059
  SColumnInfoData* pCol = pInput->pData[0];
13,122,467✔
2060
  int32_t          type = pCol->info.type;
13,122,467✔
2061

2062
  SAPercentileInfo* pInfo = GET_ROWCELL_INTERBUF(pResInfo);
13,122,467✔
2063

2064
  int32_t start = pInput->startRowIndex;
13,122,467✔
2065
  if (pInfo->algo == APERCT_ALGO_TDIGEST) {
13,122,467✔
2066
    buildTDigestInfo(pInfo);
17,325✔
2067
    tdigestAutoFill(pInfo->pTDigest, COMPRESSION);
17,325✔
2068
    for (int32_t i = start; i < pInput->numOfRows + start; ++i) {
1,324,983✔
2069
      if (colDataIsNull_f(pCol->nullbitmap, i)) {
1,307,683✔
2070
        continue;
210,161✔
2071
      }
2072
      numOfElems += 1;
1,097,522✔
2073
      char* data = colDataGetData(pCol, i);
1,097,522!
2074

2075
      double  v = 0;  // value
1,097,522✔
2076
      int64_t w = 1;  // weigth
1,097,522✔
2077
      GET_TYPED_DATA(v, double, type, data);
1,097,522✔
2078
      int32_t code = tdigestAdd(pInfo->pTDigest, v, w);
1,097,522✔
2079
      if (code != TSDB_CODE_SUCCESS) {
1,097,499!
2080
        return code;
×
2081
      }
2082
    }
2083
  } else {
2084
    // might be a race condition here that pHisto can be overwritten or setup function
2085
    // has not been called, need to relink the buffer pHisto points to.
2086
    buildHistogramInfo(pInfo);
13,105,142✔
2087
    qDebug("%s before add %d elements into histogram, total:%" PRId64 ", numOfEntry:%d, pHisto:%p, elems: %p",
13,105,140✔
2088
           __FUNCTION__, numOfElems, pInfo->pHisto->numOfElems, pInfo->pHisto->numOfEntries, pInfo->pHisto,
2089
           pInfo->pHisto->elems);
2090
    for (int32_t i = start; i < pInput->numOfRows + start; ++i) {
49,522,365✔
2091
      if (colDataIsNull_f(pCol->nullbitmap, i)) {
36,417,275✔
2092
        continue;
688,320✔
2093
      }
2094
      numOfElems += 1;
35,728,955✔
2095
      char* data = colDataGetData(pCol, i);
35,728,955!
2096

2097
      double v = 0;
35,728,955✔
2098
      GET_TYPED_DATA(v, double, type, data);
35,728,955!
2099
      int32_t code = tHistogramAdd(&pInfo->pHisto, v);
35,728,955✔
2100
      if (code != TSDB_CODE_SUCCESS) {
35,728,901!
2101
        return code;
×
2102
      }
2103
    }
2104

2105
    qDebug("%s after add %d elements into histogram, total:%" PRId64 ", numOfEntry:%d, pHisto:%p, elems: %p",
13,105,090✔
2106
           __FUNCTION__, numOfElems, pInfo->pHisto->numOfElems, pInfo->pHisto->numOfEntries, pInfo->pHisto,
2107
           pInfo->pHisto->elems);
2108
  }
2109

2110
  SET_VAL(pResInfo, numOfElems, 1);
13,122,470✔
2111
  return TSDB_CODE_SUCCESS;
13,122,470✔
2112
}
2113

2114
static int32_t apercentileTransferInfo(SAPercentileInfo* pInput, SAPercentileInfo* pOutput, bool* hasRes) {
1,899,362✔
2115
  pOutput->percent = pInput->percent;
1,899,362✔
2116
  pOutput->algo = pInput->algo;
1,899,362✔
2117
  if (pOutput->algo == APERCT_ALGO_TDIGEST) {
1,899,362✔
2118
    buildTDigestInfo(pInput);
93✔
2119
    tdigestAutoFill(pInput->pTDigest, COMPRESSION);
93✔
2120

2121
    if (pInput->pTDigest->num_centroids == 0 && pInput->pTDigest->num_buffered_pts == 0) {
93✔
2122
      return TSDB_CODE_SUCCESS;
1✔
2123
    }
2124

2125
    if (hasRes) {
92✔
2126
      *hasRes = true;
90✔
2127
    }
2128

2129
    buildTDigestInfo(pOutput);
92✔
2130
    TDigest* pTDigest = pOutput->pTDigest;
92✔
2131
    tdigestAutoFill(pTDigest, COMPRESSION);
92✔
2132

2133
    if (pTDigest->num_centroids <= 0 && pTDigest->num_buffered_pts == 0) {
92!
2134
      (void)memcpy(pTDigest, pInput->pTDigest, (size_t)TDIGEST_SIZE(COMPRESSION));
90✔
2135
      tdigestAutoFill(pTDigest, COMPRESSION);
90✔
2136
    } else {
2137
      int32_t code = tdigestMerge(pTDigest, pInput->pTDigest);
2✔
2138
      if (TSDB_CODE_SUCCESS != code) {
2!
2139
        return code;
×
2140
      }
2141
    }
2142
  } else {
2143
    buildHistogramInfo(pInput);
1,899,269✔
2144
    if (pInput->pHisto->numOfElems <= 0) {
1,899,269✔
2145
      return TSDB_CODE_SUCCESS;
153✔
2146
    }
2147

2148
    if (hasRes) {
1,899,116✔
2149
      *hasRes = true;
1,899,114✔
2150
    }
2151

2152
    buildHistogramInfo(pOutput);
1,899,116✔
2153
    SHistogramInfo* pHisto = pOutput->pHisto;
1,899,116✔
2154

2155
    if (pHisto->numOfElems <= 0) {
1,899,116✔
2156
      (void)memcpy(pHisto, pInput->pHisto, sizeof(SHistogramInfo) + sizeof(SHistBin) * (MAX_HISTOGRAM_BIN + 1));
1,898,762✔
2157
      pHisto->elems = (SHistBin*)((char*)pHisto + sizeof(SHistogramInfo));
1,898,762✔
2158

2159
      qDebug("%s merge histo, total:%" PRId64 ", entry:%d, %p", __FUNCTION__, pHisto->numOfElems, pHisto->numOfEntries,
1,898,762✔
2160
             pHisto);
2161
    } else {
2162
      pHisto->elems = (SHistBin*)((char*)pHisto + sizeof(SHistogramInfo));
354✔
2163
      qDebug("%s input histogram, elem:%" PRId64 ", entry:%d, %p", __FUNCTION__, pHisto->numOfElems,
354✔
2164
             pHisto->numOfEntries, pInput->pHisto);
2165

2166
      SHistogramInfo* pRes = NULL;
354✔
2167
      int32_t         code = tHistogramMerge(pHisto, pInput->pHisto, MAX_HISTOGRAM_BIN, &pRes);
354✔
2168
      if (TSDB_CODE_SUCCESS != code) {
354!
2169
        tHistogramDestroy(&pRes);
×
2170
        return code;
×
2171
      }
2172
      (void)memcpy(pHisto, pRes, sizeof(SHistogramInfo) + sizeof(SHistBin) * MAX_HISTOGRAM_BIN);
354✔
2173
      pHisto->elems = (SHistBin*)((char*)pHisto + sizeof(SHistogramInfo));
354✔
2174

2175
      qDebug("%s merge histo, total:%" PRId64 ", entry:%d, %p", __FUNCTION__, pHisto->numOfElems, pHisto->numOfEntries,
354✔
2176
             pHisto);
2177
      tHistogramDestroy(&pRes);
354✔
2178
    }
2179
  }
2180
  return TSDB_CODE_SUCCESS;
1,899,208✔
2181
}
2182

2183
int32_t apercentileFunctionMerge(SqlFunctionCtx* pCtx) {
1,899,290✔
2184
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
1,899,290✔
2185

2186
  SInputColumnInfoData* pInput = &pCtx->input;
1,899,290✔
2187

2188
  SColumnInfoData* pCol = pInput->pData[0];
1,899,290✔
2189
  if (pCol->info.type != TSDB_DATA_TYPE_BINARY) {
1,899,290!
2190
    return TSDB_CODE_FUNC_FUNTION_PARA_TYPE;
×
2191
  }
2192

2193
  SAPercentileInfo* pInfo = GET_ROWCELL_INTERBUF(pResInfo);
1,899,290✔
2194

2195
  qDebug("%s total %" PRId64 " rows will merge, %p", __FUNCTION__, pInput->numOfRows, pInfo->pHisto);
1,899,290✔
2196

2197
  bool    hasRes = false;
1,899,290✔
2198
  int32_t start = pInput->startRowIndex;
1,899,290✔
2199
  for (int32_t i = start; i < start + pInput->numOfRows; ++i) {
3,798,648✔
2200
    char* data = colDataGetData(pCol, i);
1,899,358!
2201

2202
    SAPercentileInfo* pInputInfo = (SAPercentileInfo*)varDataVal(data);
1,899,358✔
2203
    int32_t           code = apercentileTransferInfo(pInputInfo, pInfo, &hasRes);
1,899,358✔
2204
    if (TSDB_CODE_SUCCESS != code) {
1,899,358!
2205
      return code;
×
2206
    }
2207
  }
2208

2209
  if (pInfo->algo != APERCT_ALGO_TDIGEST) {
1,899,290✔
2210
    buildHistogramInfo(pInfo);
1,899,199✔
2211
    qDebug("%s after merge, total:%" PRId64 ", numOfEntry:%d, %p", __FUNCTION__, pInfo->pHisto->numOfElems,
1,899,199✔
2212
           pInfo->pHisto->numOfEntries, pInfo->pHisto);
2213
  }
2214

2215
  SET_VAL(pResInfo, hasRes ? 1 : 0, 1);
1,899,290✔
2216
  return TSDB_CODE_SUCCESS;
1,899,290✔
2217
}
2218

2219
int32_t apercentileFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
12,938,167✔
2220
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
12,938,167✔
2221
  SAPercentileInfo*    pInfo = (SAPercentileInfo*)GET_ROWCELL_INTERBUF(pResInfo);
12,938,167✔
2222

2223
  if (pInfo->algo == APERCT_ALGO_TDIGEST) {
12,938,167✔
2224
    buildTDigestInfo(pInfo);
12,822✔
2225
    tdigestAutoFill(pInfo->pTDigest, COMPRESSION);
12,822✔
2226
    if (pInfo->pTDigest->size > 0) {
12,823!
2227
      pInfo->result = tdigestQuantile(pInfo->pTDigest, pInfo->percent / 100);
12,823✔
2228
    } else {  // no need to free
2229
      // setNull(pCtx->pOutput, pCtx->outputType, pCtx->outputBytes);
2230
      return TSDB_CODE_SUCCESS;
×
2231
    }
2232
  } else {
2233
    buildHistogramInfo(pInfo);
12,925,345✔
2234
    if (pInfo->pHisto->numOfElems > 0) {
12,925,336✔
2235
      qDebug("%s get the final res, elements:%" PRId64 ", numOfEntry:%d, pHisto:%p, elems:%p", __FUNCTION__,
12,880,220✔
2236
             pInfo->pHisto->numOfElems, pInfo->pHisto->numOfEntries, pInfo->pHisto, pInfo->pHisto->elems);
2237

2238
      double  ratio[] = {pInfo->percent};
12,880,221✔
2239
      double* res = NULL;
12,880,221✔
2240
      int32_t code = tHistogramUniform(pInfo->pHisto, ratio, 1, &res);
12,880,221✔
2241
      if (TSDB_CODE_SUCCESS != code) {
12,880,223!
2242
        taosMemoryFree(res);
×
2243
        return code;
×
2244
      }
2245
      pInfo->result = *res;
12,880,223✔
2246
      // memcpy(pCtx->pOutput, res, sizeof(double));
2247
      taosMemoryFree(res);
12,880,223✔
2248
    } else {  // no need to free
2249
      // setNull(pCtx->pOutput, pCtx->outputType, pCtx->outputBytes);
2250
      // return TSDB_CODE_SUCCESS;
2251
      qDebug("%s get the final res, elements:%" PRId64 ", numOfEntry:%d. result is null", __FUNCTION__,
45,116✔
2252
             pInfo->pHisto->numOfElems, pInfo->pHisto->numOfEntries);
2253
    }
2254
  }
2255

2256
  return functionFinalize(pCtx, pBlock);
12,938,165✔
2257
}
2258

2259
int32_t apercentilePartialFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
1,899,036✔
2260
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
1,899,036✔
2261
  SAPercentileInfo*    pInfo = (SAPercentileInfo*)GET_ROWCELL_INTERBUF(pResInfo);
1,899,036✔
2262

2263
  int32_t resultBytes = getApercentileMaxSize();
1,899,036✔
2264
  char*   res = taosMemoryCalloc(resultBytes + VARSTR_HEADER_SIZE, sizeof(char));
1,899,036!
2265
  if (NULL == res) {
1,899,036!
2266
    return terrno;
×
2267
  }
2268

2269
  if (pInfo->algo == APERCT_ALGO_TDIGEST) {
1,899,036✔
2270
    (void)memcpy(varDataVal(res), pInfo, resultBytes);
91✔
2271
    varDataSetLen(res, resultBytes);
91✔
2272
  } else {
2273
    (void)memcpy(varDataVal(res), pInfo, resultBytes);
1,898,945✔
2274
    varDataSetLen(res, resultBytes);
1,898,945✔
2275
  }
2276

2277
  int32_t          slotId = pCtx->pExpr->base.resSchema.slotId;
1,899,036✔
2278
  SColumnInfoData* pCol = taosArrayGet(pBlock->pDataBlock, slotId);
1,899,036✔
2279
  if (NULL == pCol) {
1,899,036!
2280
    taosMemoryFree(res);
×
2281
    return TSDB_CODE_OUT_OF_RANGE;
×
2282
  }
2283

2284
  int32_t code = colDataSetVal(pCol, pBlock->info.rows, res, false);
1,899,036✔
2285

2286
  taosMemoryFree(res);
1,899,036!
2287
  return code;
1,899,036✔
2288
}
2289

2290
int32_t apercentileCombine(SqlFunctionCtx* pDestCtx, SqlFunctionCtx* pSourceCtx) {
4✔
2291
  SResultRowEntryInfo* pDResInfo = GET_RES_INFO(pDestCtx);
4✔
2292
  SAPercentileInfo*    pDBuf = GET_ROWCELL_INTERBUF(pDResInfo);
4✔
2293

2294
  SResultRowEntryInfo* pSResInfo = GET_RES_INFO(pSourceCtx);
4✔
2295
  SAPercentileInfo*    pSBuf = GET_ROWCELL_INTERBUF(pSResInfo);
4✔
2296

2297
  qDebug("%s start to combine apercentile, %p", __FUNCTION__, pDBuf->pHisto);
4!
2298

2299
  int32_t code = apercentileTransferInfo(pSBuf, pDBuf, NULL);
4✔
2300
  if (TSDB_CODE_SUCCESS != code) {
4!
2301
    return code;
×
2302
  }
2303
  pDResInfo->numOfRes = TMAX(pDResInfo->numOfRes, pSResInfo->numOfRes);
4✔
2304
  pDResInfo->isNullRes &= pSResInfo->isNullRes;
4✔
2305
  return TSDB_CODE_SUCCESS;
4✔
2306
}
2307

2308
// TODO: change this function when block data info pks changed
2309
static int32_t comparePkDataWithSValue(int8_t pkType, char* pkData, SValue* pVal, int32_t order) {
11✔
2310
  char numVal[8] = {0};
11✔
2311
  switch (pkType) {
11!
2312
    case TSDB_DATA_TYPE_INT:
11✔
2313
      *(int32_t*)numVal = (int32_t)pVal->val;
11✔
2314
      break;
11✔
2315
    case TSDB_DATA_TYPE_UINT:
×
2316
      *(uint32_t*)numVal = (uint32_t)pVal->val;
×
2317
      break;
×
2318
    case TSDB_DATA_TYPE_BIGINT:
×
2319
      *(int64_t*)numVal = (int64_t)pVal->val;
×
2320
      break;
×
2321
    case TSDB_DATA_TYPE_UBIGINT:
×
2322
      *(uint64_t*)numVal = (uint64_t)pVal->val;
×
2323
      break;
×
2324
    default:
×
2325
      break;
×
2326
  }
2327
  char*         blockData = (IS_NUMERIC_TYPE(pkType)) ? (char*)numVal : (char*)pVal->pData;
11!
2328
  __compar_fn_t fn = getKeyComparFunc(pkType, order);
11✔
2329
  return fn(pkData, blockData);
11✔
2330
}
2331

2332
EFuncDataRequired firstDynDataReq(void* pRes, SDataBlockInfo* pBlockInfo) {
6,467✔
2333
  SResultRowEntryInfo* pEntry = (SResultRowEntryInfo*)pRes;
6,467✔
2334

2335
  // not initialized yet, data is required
2336
  if (pEntry == NULL) {
6,467!
2337
    return FUNC_DATA_REQUIRED_DATA_LOAD;
×
2338
  }
2339

2340
  SFirstLastRes* pResult = GET_ROWCELL_INTERBUF(pEntry);
6,467✔
2341
  if (pResult->hasResult) {
6,467✔
2342
    if (pResult->pkBytes > 0) {
6,416✔
2343
      pResult->pkData = pResult->buf + pResult->bytes;
6✔
2344
    } else {
2345
      pResult->pkData = NULL;
6,410✔
2346
    }
2347
    if (pResult->ts < pBlockInfo->window.skey) {
6,416✔
2348
      return FUNC_DATA_REQUIRED_NOT_LOAD;
4,228✔
2349
    } else if (pResult->ts == pBlockInfo->window.skey) {
2,188✔
2350
      if (NULL == pResult->pkData) {
243✔
2351
        return FUNC_DATA_REQUIRED_NOT_LOAD;
237✔
2352
      }
2353
      if (comparePkDataWithSValue(pResult->pkType, pResult->pkData, pBlockInfo->pks + 0, TSDB_ORDER_ASC) < 0) {
6!
2354
        return FUNC_DATA_REQUIRED_NOT_LOAD;
6✔
2355
      }
2356
    }
2357
    return FUNC_DATA_REQUIRED_DATA_LOAD;
1,945✔
2358
  } else {
2359
    return FUNC_DATA_REQUIRED_DATA_LOAD;
51✔
2360
  }
2361
}
2362

2363
EFuncDataRequired lastDynDataReq(void* pRes, SDataBlockInfo* pBlockInfo) {
23,849✔
2364
  SResultRowEntryInfo* pEntry = (SResultRowEntryInfo*)pRes;
23,849✔
2365

2366
  // not initialized yet, data is required
2367
  if (pEntry == NULL) {
23,849!
2368
    return FUNC_DATA_REQUIRED_DATA_LOAD;
×
2369
  }
2370

2371
  SFirstLastRes* pResult = GET_ROWCELL_INTERBUF(pEntry);
23,849✔
2372
  if (pResult->hasResult) {
23,849✔
2373
    if (pResult->pkBytes > 0) {
23,773✔
2374
      pResult->pkData = pResult->buf + pResult->bytes;
5✔
2375
    } else {
2376
      pResult->pkData = NULL;
23,768✔
2377
    }
2378
    if (pResult->ts > pBlockInfo->window.ekey) {
23,773✔
2379
      return FUNC_DATA_REQUIRED_NOT_LOAD;
21,446✔
2380
    } else if (pResult->ts == pBlockInfo->window.ekey && pResult->pkData) {
2,327✔
2381
      if (comparePkDataWithSValue(pResult->pkType, pResult->pkData, pBlockInfo->pks + 1, TSDB_ORDER_DESC) < 0) {
5!
2382
        return FUNC_DATA_REQUIRED_NOT_LOAD;
×
2383
      }
2384
    }
2385
    return FUNC_DATA_REQUIRED_DATA_LOAD;
2,327✔
2386
  } else {
2387
    return FUNC_DATA_REQUIRED_DATA_LOAD;
76✔
2388
  }
2389
}
2390

2391
// TODO modify it to include primary key bytes
2392
int32_t getFirstLastInfoSize(int32_t resBytes, int32_t pkBytes) { return sizeof(SFirstLastRes) + resBytes + pkBytes; }
61,708,377✔
2393

2394
bool getFirstLastFuncEnv(SFunctionNode* pFunc, SFuncExecEnv* pEnv) {
1,812,135✔
2395
  SColumnNode* pNode = (SColumnNode*)nodesListGetNode(pFunc->pParameterList, 0);
1,812,135✔
2396
  // TODO: change SFunctionNode to add pk info
2397
  int32_t pkBytes = (pFunc->hasPk) ? pFunc->pkBytes : 0;
1,814,070✔
2398
  pEnv->calcMemSize = getFirstLastInfoSize(pNode->node.resType.bytes, pkBytes);
1,814,070✔
2399
  return true;
1,813,666✔
2400
}
2401

2402
bool getSelectivityFuncEnv(SFunctionNode* pFunc, SFuncExecEnv* pEnv) {
1,232,538✔
2403
  SColumnNode* pNode = (SColumnNode*)nodesListGetNode(pFunc->pParameterList, 0);
1,232,538✔
2404
  pEnv->calcMemSize = pNode->node.resType.bytes;
1,234,089✔
2405
  return true;
1,234,089✔
2406
}
2407

2408
bool getGroupKeyFuncEnv(SFunctionNode* pFunc, SFuncExecEnv* pEnv) {
253,161✔
2409
  SColumnNode* pNode = (SColumnNode*)nodesListGetNode(pFunc->pParameterList, 0);
253,161✔
2410
  pEnv->calcMemSize = sizeof(SGroupKeyInfo) + pNode->node.resType.bytes;
253,495✔
2411
  return true;
253,495✔
2412
}
2413

2414
static FORCE_INLINE TSKEY getRowPTs(SColumnInfoData* pTsColInfo, int32_t rowIndex) {
2415
  if (pTsColInfo == NULL || pTsColInfo->pData == NULL) {
305,988,620!
2416
    return 0;
×
2417
  }
2418

2419
  return *(TSKEY*)colDataGetData(pTsColInfo, rowIndex);
306,035,897!
2420
}
2421

2422
int32_t firstLastFunctionSetup(SqlFunctionCtx* pCtx, SResultRowEntryInfo* pResInfo) {
23,141,363✔
2423
  if (pResInfo->initialized) {
23,141,363!
2424
    return TSDB_CODE_SUCCESS;
×
2425
  }
2426
  if (TSDB_CODE_SUCCESS != functionSetup(pCtx, pResInfo)) {
23,141,363!
2427
    return TSDB_CODE_FUNC_SETUP_ERROR;
×
2428
  }
2429

2430
  SFirstLastRes*        pRes = GET_ROWCELL_INTERBUF(pResInfo);
23,142,043✔
2431
  pRes->nullTupleSaved = false;
23,142,043✔
2432
  pRes->nullTuplePos.pageId = -1;
23,142,043✔
2433
  return TSDB_CODE_SUCCESS;
23,142,043✔
2434
}
2435

2436
static int32_t prepareBuf(SqlFunctionCtx* pCtx) {
185,867,975✔
2437
  if (pCtx->subsidiaries.rowLen == 0) {
185,867,975✔
2438
    int32_t rowLen = 0;
606,133✔
2439
    for (int32_t j = 0; j < pCtx->subsidiaries.num; ++j) {
1,218,121✔
2440
      SqlFunctionCtx* pc = pCtx->subsidiaries.pCtx[j];
611,988✔
2441
      rowLen += pc->pExpr->base.resSchema.bytes;
611,988✔
2442
    }
2443

2444
    pCtx->subsidiaries.rowLen = rowLen + pCtx->subsidiaries.num * sizeof(bool);
606,133✔
2445
    pCtx->subsidiaries.buf = taosMemoryMalloc(pCtx->subsidiaries.rowLen);
606,133!
2446
    if (NULL == pCtx->subsidiaries.buf) {
601,156!
2447
      return terrno;
×
2448
    }
2449
  }
2450
  return TSDB_CODE_SUCCESS;
185,862,998✔
2451
}
2452

2453
static int32_t firstlastSaveTupleData(const SSDataBlock* pSrcBlock, int32_t rowIndex, SqlFunctionCtx* pCtx,
188,372,392✔
2454
                                      SFirstLastRes* pInfo, bool noElements) {
2455
  int32_t code = TSDB_CODE_SUCCESS;
188,372,392✔
2456

2457
  if (pCtx->subsidiaries.num <= 0) {
188,372,392✔
2458
    return TSDB_CODE_SUCCESS;
101,239,627✔
2459
  }
2460

2461
  if (!pInfo->hasResult) {
87,132,765✔
2462
    code = saveTupleData(pCtx, rowIndex, pSrcBlock, &pInfo->pos);
76,785,648✔
2463
  } else if (!noElements) {
10,347,117!
2464
    code = updateTupleData(pCtx, rowIndex, pSrcBlock, &pInfo->pos);
10,390,284✔
2465
  } else { } // dothing
2466

2467
  return code;
87,079,796✔
2468
}
2469

2470
static int32_t doSaveCurrentVal(SqlFunctionCtx* pCtx, int32_t rowIndex, int64_t currentTs, char* pkData, int32_t type,
88,969,431✔
2471
                                char* pData) {
2472
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
88,969,431✔
2473
  SFirstLastRes*       pInfo = GET_ROWCELL_INTERBUF(pResInfo);
88,969,431✔
2474

2475
  if (IS_VAR_DATA_TYPE(type)) {
88,969,431!
2476
    if (type == TSDB_DATA_TYPE_JSON) {
10,530,415!
2477
      pInfo->bytes = getJsonValueLen(pData);
×
2478
    } else {
2479
      pInfo->bytes = varDataTLen(pData);
10,530,415✔
2480
    }
2481
  }
2482

2483
  (void)memcpy(pInfo->buf, pData, pInfo->bytes);
88,969,431✔
2484
  if (pkData != NULL) {
88,969,431✔
2485
    if (IS_VAR_DATA_TYPE(pInfo->pkType)) {
30,118!
2486
      if (pInfo->pkType == TSDB_DATA_TYPE_JSON) {
24!
2487
        pInfo->pkBytes = getJsonValueLen(pkData);
×
2488
      } else {
2489
        pInfo->pkBytes = varDataTLen(pkData);
24✔
2490
      }
2491
    }
2492
    (void)memcpy(pInfo->buf + pInfo->bytes, pkData, pInfo->pkBytes);
30,118✔
2493
    pInfo->pkData = pInfo->buf + pInfo->bytes;
30,118✔
2494
  }
2495

2496
  pInfo->ts = currentTs;
88,969,431✔
2497
  int32_t code = firstlastSaveTupleData(pCtx->pSrcBlock, rowIndex, pCtx, pInfo, false);
88,969,431✔
2498
  if (code != TSDB_CODE_SUCCESS) {
89,020,179!
2499
    return code;
×
2500
  }
2501

2502
  pInfo->hasResult = true;
89,020,179✔
2503
  return TSDB_CODE_SUCCESS;
89,020,179✔
2504
}
2505

2506
// This ordinary first function does not care if current scan is ascending order or descending order scan
2507
// the OPTIMIZED version of first function will only handle the ascending order scan
2508
int32_t firstFunction(SqlFunctionCtx* pCtx) {
48,380,146✔
2509
  int32_t numOfElems = 0;
48,380,146✔
2510

2511
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
48,380,146✔
2512
  SFirstLastRes*       pInfo = GET_ROWCELL_INTERBUF(pResInfo);
48,380,146✔
2513

2514
  SInputColumnInfoData* pInput = &pCtx->input;
48,380,146✔
2515
  SColumnInfoData*      pInputCol = pInput->pData[0];
48,380,146✔
2516

2517
  pInfo->bytes = pInputCol->info.bytes;
48,380,146✔
2518

2519
  if (IS_NULL_TYPE(pInputCol->info.type)) {
48,380,146✔
2520
    return TSDB_CODE_SUCCESS;
5,067✔
2521
  }
2522

2523
  SColumnInfoData* pkCol = pInput->pPrimaryKey;
48,375,079✔
2524
  pInfo->pkType = -1;
48,375,079✔
2525
  __compar_fn_t pkCompareFn = NULL;
48,375,079✔
2526
  if (pCtx->hasPrimaryKey) {
48,375,079✔
2527
    pInfo->pkType = pkCol->info.type;
51✔
2528
    pInfo->pkBytes = pkCol->info.bytes;
51✔
2529
    pkCompareFn = getKeyComparFunc(pInfo->pkType, TSDB_ORDER_ASC);
51✔
2530
  }
2531

2532
  // All null data column, return directly.
2533
  if (pInput->colDataSMAIsSet && (pInput->pColumnDataAgg[0]->numOfNull == pInput->totalRows) &&
48,474,867!
2534
      pInputCol->hasNull == true) {
×
2535
    // save selectivity value for column consisted of all null values
2536
    int32_t code = firstlastSaveTupleData(pCtx->pSrcBlock, pInput->startRowIndex, pCtx, pInfo, true);
×
2537
    if (code != TSDB_CODE_SUCCESS) {
×
2538
      return code;
×
2539
    }
2540
    pInfo->nullTupleSaved = true;
×
2541
    return TSDB_CODE_SUCCESS;
×
2542
  }
2543

2544
  SColumnDataAgg* pColAgg = (pInput->colDataSMAIsSet) ? pInput->pColumnDataAgg[0] : NULL;
48,474,867!
2545

2546
  TSKEY startKey = getRowPTs(pInput->pPTS, 0);
48,474,867!
2547
  TSKEY endKey = getRowPTs(pInput->pPTS, pInput->totalRows - 1);
48,474,867!
2548

2549
  int32_t blockDataOrder = (startKey <= endKey) ? TSDB_ORDER_ASC : TSDB_ORDER_DESC;
48,474,867✔
2550

2551
  //  please ref. to the comment in lastRowFunction for the reason why disabling the opt version of last/first
2552
  //  function. we will use this opt implementation in an new version that is only available in scan subplan
2553
#if 0
2554
  if (blockDataOrder == TSDB_ORDER_ASC) {
2555
    // filter according to current result firstly
2556
    if (pResInfo->numOfRes > 0) {
2557
      if (pInfo->ts < startKey) {
2558
        return TSDB_CODE_SUCCESS;
2559
      }
2560
    }
2561

2562
    for (int32_t i = pInput->startRowIndex; i < pInput->startRowIndex + pInput->numOfRows; ++i) {
2563
      if (pInputCol->hasNull && colDataIsNull(pInputCol, pInput->totalRows, i, pColAgg)) {
2564
        continue;
2565
      }
2566

2567
      numOfElems++;
2568

2569
      char* data = colDataGetData(pInputCol, i);
2570
      TSKEY cts = getRowPTs(pInput->pPTS, i);
2571
      if (pResInfo->numOfRes == 0 || pInfo->ts > cts) {
2572
        doSaveCurrentVal(pCtx, i, cts, pInputCol->info.type, data);
2573
        break;
2574
      }
2575
    }
2576
  } else {
2577
    // in case of descending order time stamp serial, which usually happens as the results of the nest query,
2578
    // all data needs to be check.
2579
    if (pResInfo->numOfRes > 0) {
2580
      if (pInfo->ts < endKey) {
2581
        return TSDB_CODE_SUCCESS;
2582
      }
2583
    }
2584

2585
    for (int32_t i = pInput->numOfRows + pInput->startRowIndex - 1; i >= pInput->startRowIndex; --i) {
2586
      if (pInputCol->hasNull && colDataIsNull(pInputCol, pInput->totalRows, i, pColAgg)) {
2587
        continue;
2588
      }
2589

2590
      numOfElems++;
2591

2592
      char* data = colDataGetData(pInputCol, i);
2593
      TSKEY cts = getRowPTs(pInput->pPTS, i);
2594

2595
      if (pResInfo->numOfRes == 0 || pInfo->ts > cts) {
2596
        doSaveCurrentVal(pCtx, i, cts, pInputCol->info.type, data);
2597
        break;
2598
      }
2599
    }
2600
  }
2601
#else
2602
  int64_t* pts = (int64_t*)pInput->pPTS->pData;
48,474,867✔
2603

2604
  int     from = -1;
48,474,867✔
2605
  int32_t i = -1;
48,474,867✔
2606
  while (funcInputGetNextRowIndex(pInput, from, true, &i, &from)) {
146,978,343✔
2607
    if (pInputCol->hasNull && colDataIsNull(pInputCol, pInput->totalRows, i, pColAgg)) {
131,855,004!
2608
      continue;
79,101✔
2609
    }
2610

2611
    numOfElems++;
98,449,373✔
2612
    char* data = colDataGetData(pInputCol, i);
98,449,373!
2613
    char* pkData = NULL;
98,449,373✔
2614
    if (pCtx->hasPrimaryKey) {
98,449,373✔
2615
      pkData = colDataGetData(pkCol, i);
153!
2616
    }
2617
    TSKEY cts = pts[i];
98,449,373✔
2618
    if (pResInfo->numOfRes == 0 || pInfo->ts > cts ||
98,449,373✔
2619
        (pInfo->ts == cts && pkCompareFn && pkCompareFn(pkData, pInfo->pkData) < 0)) {
57,629,568!
2620
      int32_t code = doSaveCurrentVal(pCtx, i, cts, pkData, pInputCol->info.type, data);
40,819,805✔
2621
      if (code != TSDB_CODE_SUCCESS) {
40,794,807!
2622
        return code;
×
2623
      }
2624
      pResInfo->numOfRes = 1;
40,794,807✔
2625
    }
2626
  }
2627
#endif
2628

2629
  if (numOfElems == 0) {
48,088,151✔
2630
    // save selectivity value for column consisted of all null values
2631
    int32_t code = firstlastSaveTupleData(pCtx->pSrcBlock, pInput->startRowIndex, pCtx, pInfo, true);
24,925✔
2632
    if (code != TSDB_CODE_SUCCESS) {
24,925!
2633
      return code;
×
2634
    }
2635
    pInfo->nullTupleSaved = true;
24,925✔
2636
  }
2637
  SET_VAL(pResInfo, numOfElems, 1);
48,088,151✔
2638
  return TSDB_CODE_SUCCESS;
48,088,151✔
2639
}
2640

2641
int32_t lastFunction(SqlFunctionCtx* pCtx) {
44,758,433✔
2642
  int32_t numOfElems = 0;
44,758,433✔
2643

2644
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
44,758,433✔
2645
  SFirstLastRes*       pInfo = GET_ROWCELL_INTERBUF(pResInfo);
44,758,433✔
2646

2647
  SInputColumnInfoData* pInput = &pCtx->input;
44,758,433✔
2648
  SColumnInfoData*      pInputCol = pInput->pData[0];
44,758,433✔
2649

2650
  int32_t type = pInputCol->info.type;
44,758,433✔
2651
  int32_t bytes = pInputCol->info.bytes;
44,758,433✔
2652

2653
  if (IS_NULL_TYPE(type)) {
44,758,433✔
2654
    return TSDB_CODE_SUCCESS;
5,071✔
2655
  }
2656
  pInfo->bytes = bytes;
44,753,362✔
2657

2658
  SColumnInfoData* pkCol = pInput->pPrimaryKey;
44,753,362✔
2659
  pInfo->pkType = -1;
44,753,362✔
2660
  __compar_fn_t pkCompareFn = NULL;
44,753,362✔
2661
  if (pCtx->hasPrimaryKey) {
44,753,362✔
2662
    pInfo->pkType = pkCol->info.type;
30,067✔
2663
    pInfo->pkBytes = pkCol->info.bytes;
30,067✔
2664
    pkCompareFn = getKeyComparFunc(pInfo->pkType, TSDB_ORDER_DESC);
30,067✔
2665
  }
2666

2667
  // All null data column, return directly.
2668
  if (pInput->colDataSMAIsSet && (pInput->pColumnDataAgg[0]->numOfNull == pInput->totalRows) &&
44,842,981!
2669
      pInputCol->hasNull == true) {
×
2670
    // save selectivity value for column consisted of all null values
2671
    int32_t code = firstlastSaveTupleData(pCtx->pSrcBlock, pInput->startRowIndex, pCtx, pInfo, true);
×
2672
    if (code != TSDB_CODE_SUCCESS) {
×
2673
      return code;
×
2674
    }
2675
    pInfo->nullTupleSaved = true;
×
2676
    return TSDB_CODE_SUCCESS;
×
2677
  }
2678

2679
  SColumnDataAgg* pColAgg = (pInput->colDataSMAIsSet) ? pInput->pColumnDataAgg[0] : NULL;
44,842,981!
2680

2681
  TSKEY startKey = getRowPTs(pInput->pPTS, 0);
44,842,981!
2682
  TSKEY endKey = getRowPTs(pInput->pPTS, pInput->totalRows - 1);
44,842,981!
2683

2684
  int32_t blockDataOrder = (startKey <= endKey) ? TSDB_ORDER_ASC : TSDB_ORDER_DESC;
44,842,981✔
2685

2686
  //  please ref. to the comment in lastRowFunction for the reason why disabling the opt version of last/first function.
2687
#if 0
2688
  if (blockDataOrder == TSDB_ORDER_ASC) {
2689
    for (int32_t i = pInput->numOfRows + pInput->startRowIndex - 1; i >= pInput->startRowIndex; --i) {
2690
      if (pInputCol->hasNull && colDataIsNull(pInputCol, pInput->totalRows, i, pColAgg)) {
2691
        continue;
2692
      }
2693

2694
      numOfElems++;
2695

2696
      char* data = colDataGetData(pInputCol, i);
2697
      TSKEY cts = getRowPTs(pInput->pPTS, i);
2698
      if (pResInfo->numOfRes == 0 || pInfo->ts < cts) {
2699
        doSaveCurrentVal(pCtx, i, cts, type, data);
2700
      }
2701

2702
      break;
2703
    }
2704
  } else {  // descending order
2705
    for (int32_t i = pInput->startRowIndex; i < pInput->numOfRows + pInput->startRowIndex; ++i) {
2706
      if (pInputCol->hasNull && colDataIsNull(pInputCol, pInput->totalRows, i, pColAgg)) {
2707
        continue;
2708
      }
2709

2710
      numOfElems++;
2711

2712
      char* data = colDataGetData(pInputCol, i);
2713
      TSKEY cts = getRowPTs(pInput->pPTS, i);
2714
      if (pResInfo->numOfRes == 0 || pInfo->ts < cts) {
2715
        doSaveCurrentVal(pCtx, i, cts, type, data);
2716
      }
2717
      break;
2718
    }
2719
  }
2720
#else
2721
  int64_t* pts = (int64_t*)pInput->pPTS->pData;
44,842,981✔
2722

2723
#if 0
2724
    for (int32_t i = pInput->startRowIndex; i < pInput->numOfRows + pInput->startRowIndex; ++i) {
2725
      if (pInputCol->hasNull && colDataIsNull(pInputCol, pInput->totalRows, i, pColAgg)) {
2726
        continue;
2727
      }
2728

2729
      numOfElems++;
2730
      if (pResInfo->numOfRes == 0 || pInfo->ts < pts[i]) {
2731
        char* data = colDataGetData(pInputCol, i);
2732
        doSaveCurrentVal(pCtx, i, pts[i], type, data);
2733
        pResInfo->numOfRes = 1;
2734
      }
2735
    }
2736
#else
2737

2738
  // todo refactor
2739
  if (!pInputCol->hasNull && !pCtx->hasPrimaryKey) {
72,796,637✔
2740
    numOfElems = 1;
27,948,950✔
2741

2742
    int32_t round = pInput->numOfRows >> 2;
27,948,950✔
2743
    int32_t reminder = pInput->numOfRows & 0x03;
27,948,950✔
2744

2745
    for (int32_t i = pInput->startRowIndex, tick = 0; tick < round; i += 4, tick += 1) {
41,529,995✔
2746
      int64_t cts = pts[i];
13,575,604✔
2747
      int32_t chosen = i;
13,575,604✔
2748

2749
      if (cts < pts[i + 1]) {
13,575,604✔
2750
        cts = pts[i + 1];
4,910,233✔
2751
        chosen = i + 1;
4,910,233✔
2752
      }
2753

2754
      if (cts < pts[i + 2]) {
13,575,604✔
2755
        cts = pts[i + 2];
4,910,301✔
2756
        chosen = i + 2;
4,910,301✔
2757
      }
2758

2759
      if (cts < pts[i + 3]) {
13,575,604✔
2760
        cts = pts[i + 3];
4,909,844✔
2761
        chosen = i + 3;
4,909,844✔
2762
      }
2763

2764
      if (pResInfo->numOfRes == 0 || pInfo->ts < cts) {
13,575,604✔
2765
        char*   data = colDataGetData(pInputCol, chosen);
3,989,985✔
2766
        int32_t code = doSaveCurrentVal(pCtx, chosen, cts, NULL, type, data);
3,989,985✔
2767
        if (code != TSDB_CODE_SUCCESS) {
3,995,426!
2768
          return code;
×
2769
        }
2770
        pResInfo->numOfRes = 1;
3,995,426✔
2771
      }
2772
    }
2773

2774
    for (int32_t i = pInput->startRowIndex + round * 4; i < pInput->startRowIndex + pInput->numOfRows; ++i) {
59,975,683✔
2775
      if (pResInfo->numOfRes == 0 || pInfo->ts < pts[i]) {
32,022,027✔
2776
        char*   data = colDataGetData(pInputCol, i);
20,525,330!
2777
        int32_t code = doSaveCurrentVal(pCtx, i, pts[i], NULL, type, data);
20,525,330✔
2778
        if (code != TSDB_CODE_SUCCESS) {
20,524,595!
2779
          return code;
×
2780
        }
2781
        pResInfo->numOfRes = 1;
20,524,595✔
2782
      }
2783
    }
2784
  } else {
2785
    int     from = -1;
16,894,031✔
2786
    int32_t i = -1;
16,894,031✔
2787
    while (funcInputGetNextRowIndex(pInput, from, false, &i, &from)) {
157,341,412✔
2788
      if (colDataIsNull(pInputCol, pInput->totalRows, i, pColAgg)) {
280,890,524✔
2789
        continue;
5,567,325✔
2790
      }
2791

2792
      numOfElems++;
134,877,937✔
2793
      char* pkData = NULL;
134,877,937✔
2794
      if (pCtx->hasPrimaryKey) {
134,877,937✔
2795
        pkData = colDataGetData(pkCol, i);
100,000,193!
2796
      }
2797
      if (pResInfo->numOfRes == 0 || pInfo->ts < pts[i] ||
134,877,937✔
2798
          (pInfo->ts == pts[i] && pkCompareFn && pkCompareFn(pkData, pInfo->pkData) < 0)) {
111,359,831!
2799
        char*   data = colDataGetData(pInputCol, i);
23,597,280!
2800
        int32_t code = doSaveCurrentVal(pCtx, i, pts[i], pkData, type, data);
23,597,280✔
2801
        if (code != TSDB_CODE_SUCCESS) {
23,599,399!
2802
          return code;
×
2803
        }
2804
        pResInfo->numOfRes = 1;
23,599,399✔
2805
      }
2806
    }
2807
  }
2808
#endif
2809

2810
#endif
2811

2812
  // save selectivity value for column consisted of all null values
2813
  if (numOfElems == 0) {
45,055,408✔
2814
    int32_t code = firstlastSaveTupleData(pCtx->pSrcBlock, pInput->startRowIndex, pCtx, pInfo, true);
4,075,318✔
2815
    if (code != TSDB_CODE_SUCCESS) {
4,072,558!
2816
      return code;
×
2817
    }
2818
    pInfo->nullTupleSaved = true;
4,072,558✔
2819
  }
2820

2821
  return TSDB_CODE_SUCCESS;
45,052,648✔
2822
}
2823

2824
static bool firstLastTransferInfoImpl(SFirstLastRes* pInput, SFirstLastRes* pOutput, bool isFirst) {
55,715,677✔
2825
  if (!pInput->hasResult) {
55,715,677✔
2826
    return false;
2✔
2827
  }
2828
  __compar_fn_t pkCompareFn = NULL;
55,715,675✔
2829
  if (pInput->pkData) {
55,715,675✔
2830
    pkCompareFn = getKeyComparFunc(pInput->pkType, (isFirst) ? TSDB_ORDER_ASC : TSDB_ORDER_DESC);
52✔
2831
  }
2832
  if (pOutput->hasResult) {
55,717,225✔
2833
    if (isFirst) {
11,206,235✔
2834
      if (pInput->ts > pOutput->ts ||
8,571,655✔
2835
          (pInput->ts == pOutput->ts && pkCompareFn && pkCompareFn(pInput->pkData, pOutput->pkData) > 0)) {
8,571,193!
2836
        return false;
462✔
2837
      }
2838
    } else {
2839
      if (pInput->ts < pOutput->ts ||
2,634,580✔
2840
          (pInput->ts == pOutput->ts && pkCompareFn && pkCompareFn(pInput->pkData, pOutput->pkData) > 0)) {
2,631,847!
2841
        return false;
2,733✔
2842
      }
2843
    }
2844
  }
2845

2846
  pOutput->isNull = pInput->isNull;
55,714,030✔
2847
  pOutput->ts = pInput->ts;
55,714,030✔
2848
  pOutput->bytes = pInput->bytes;
55,714,030✔
2849
  pOutput->pkType = pInput->pkType;
55,714,030✔
2850

2851
  (void)memcpy(pOutput->buf, pInput->buf, pOutput->bytes);
55,714,030✔
2852
  if (pInput->pkData) {
55,714,030✔
2853
    pOutput->pkBytes = pInput->pkBytes;
45✔
2854
    (void)memcpy(pOutput->buf + pOutput->bytes, pInput->pkData, pOutput->pkBytes);
45✔
2855
    pOutput->pkData = pOutput->buf + pOutput->bytes;
45✔
2856
  }
2857
  return true;
55,714,030✔
2858
}
2859

2860
static int32_t firstLastTransferInfo(SqlFunctionCtx* pCtx, SFirstLastRes* pInput, SFirstLastRes* pOutput, bool isFirst,
55,715,894✔
2861
                                     int32_t rowIndex) {
2862
  if (firstLastTransferInfoImpl(pInput, pOutput, isFirst)) {
55,715,894✔
2863
    int32_t code = firstlastSaveTupleData(pCtx->pSrcBlock, rowIndex, pCtx, pOutput, false);
55,713,095✔
2864
    if (TSDB_CODE_SUCCESS != code) {
55,703,906!
2865
      return code;
×
2866
    }
2867
    pOutput->hasResult = true;
55,703,906✔
2868
  }
2869
  return TSDB_CODE_SUCCESS;
55,707,172✔
2870
}
2871

2872
static int32_t firstLastFunctionMergeImpl(SqlFunctionCtx* pCtx, bool isFirstQuery) {
44,520,117✔
2873
  SInputColumnInfoData* pInput = &pCtx->input;
44,520,117✔
2874
  SColumnInfoData*      pCol = pInput->pData[0];
44,520,117✔
2875

2876
  if (IS_NULL_TYPE(pCol->info.type)) {
44,520,117!
2877
    SET_VAL(GET_RES_INFO(pCtx), 0, 1);
×
2878
    return TSDB_CODE_SUCCESS;
×
2879
  }
2880

2881
  if (pCol->info.type != TSDB_DATA_TYPE_BINARY) {
44,520,117!
2882
    return TSDB_CODE_FUNC_FUNTION_PARA_TYPE;
×
2883
  }
2884

2885
  SFirstLastRes* pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
44,520,117✔
2886

2887
  int32_t start = pInput->startRowIndex;
44,520,117✔
2888
  int32_t numOfElems = 0;
44,520,117✔
2889

2890
  for (int32_t i = start; i < start + pInput->numOfRows; ++i) {
102,512,002✔
2891
    if (colDataIsNull_s(pCol, i)) {
116,007,244✔
2892
      continue;
2,285,313✔
2893
    }
2894
    char*          data = colDataGetData(pCol, i);
55,718,309!
2895
    SFirstLastRes* pInputInfo = (SFirstLastRes*)varDataVal(data);
55,718,309✔
2896
    if (pCtx->hasPrimaryKey) {
55,718,309✔
2897
      pInputInfo->pkData = pInputInfo->buf + pInputInfo->bytes;
52✔
2898
    } else {
2899
      pInputInfo->pkData = NULL;
55,718,257✔
2900
    }
2901

2902
    int32_t code = firstLastTransferInfo(pCtx, pInputInfo, pInfo, isFirstQuery, i);
55,718,309✔
2903
    if (code != TSDB_CODE_SUCCESS) {
55,706,572!
2904
      return code;
×
2905
    }
2906
    if (!numOfElems) {
55,706,572✔
2907
      numOfElems = pInputInfo->hasResult ? 1 : 0;
44,506,707✔
2908
    }
2909
  }
2910

2911
  if (numOfElems == 0) {
44,508,380✔
2912
    int32_t code = firstlastSaveTupleData(pCtx->pSrcBlock, pInput->startRowIndex, pCtx, pInfo, true);
8,121✔
2913
    if (code != TSDB_CODE_SUCCESS) {
8,121!
2914
      return code;
×
2915
    }
2916
    pInfo->nullTupleSaved = true;
8,121✔
2917
  }
2918

2919
  SET_VAL(GET_RES_INFO(pCtx), numOfElems, 1);
44,508,380✔
2920
  return TSDB_CODE_SUCCESS;
44,508,380✔
2921
}
2922

2923
int32_t firstFunctionMerge(SqlFunctionCtx* pCtx) { return firstLastFunctionMergeImpl(pCtx, true); }
11,354,407✔
2924

2925
int32_t lastFunctionMerge(SqlFunctionCtx* pCtx) { return firstLastFunctionMergeImpl(pCtx, false); }
33,169,813✔
2926

2927
int32_t firstLastFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
85,117,896✔
2928
  int32_t          code = TSDB_CODE_SUCCESS;
85,117,896✔
2929
  int32_t          slotId = pCtx->pExpr->base.resSchema.slotId;
85,117,896✔
2930
  SColumnInfoData* pCol = taosArrayGet(pBlock->pDataBlock, slotId);
85,117,896✔
2931
  if (NULL == pCol) {
85,063,866!
2932
    return TSDB_CODE_OUT_OF_RANGE;
×
2933
  }
2934

2935
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
85,063,866✔
2936
  pResInfo->isNullRes = (pResInfo->numOfRes == 0) ? 1 : 0;
85,063,866✔
2937

2938
  SFirstLastRes* pRes = GET_ROWCELL_INTERBUF(pResInfo);
85,063,866✔
2939

2940
  if (pResInfo->isNullRes) {
85,063,866✔
2941
    colDataSetNULL(pCol, pBlock->info.rows);
41,558✔
2942
    return setNullSelectivityValue(pCtx, pBlock, pBlock->info.rows);
41,558✔
2943
  }
2944
  code = colDataSetVal(pCol, pBlock->info.rows, pRes->buf, pRes->isNull || pResInfo->isNullRes);
85,022,308!
2945
  if (TSDB_CODE_SUCCESS != code) {
84,950,775!
2946
    return code;
×
2947
  }
2948

2949
  // handle selectivity
2950
  code = setSelectivityValue(pCtx, pBlock, &pRes->pos, pBlock->info.rows);
84,950,775✔
2951

2952
  return code;
84,928,275✔
2953
}
2954

2955
int32_t firstLastPartialFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
59,893,463✔
2956
  int32_t code = TSDB_CODE_SUCCESS;
59,893,463✔
2957

2958
  SResultRowEntryInfo* pEntryInfo = GET_RES_INFO(pCtx);
59,893,463✔
2959
  SFirstLastRes*       pRes = GET_ROWCELL_INTERBUF(pEntryInfo);
59,893,463✔
2960

2961
  int32_t resultBytes = getFirstLastInfoSize(pRes->bytes, pRes->pkBytes);
59,893,463✔
2962

2963
  // todo check for failure
2964
  char* res = taosMemoryCalloc(resultBytes + VARSTR_HEADER_SIZE, sizeof(char));
59,838,126!
2965
  if (NULL == res) {
60,059,869!
2966
    return terrno;
×
2967
  }
2968
  (void)memcpy(varDataVal(res), pRes, resultBytes);
60,059,869✔
2969

2970
  varDataSetLen(res, resultBytes);
60,059,869✔
2971

2972
  int32_t          slotId = pCtx->pExpr->base.resSchema.slotId;
60,059,869✔
2973
  SColumnInfoData* pCol = taosArrayGet(pBlock->pDataBlock, slotId);
60,059,869✔
2974
  if (NULL == pCol) {
59,995,401!
2975
    taosMemoryFree(res);
×
2976
    return TSDB_CODE_OUT_OF_RANGE;
×
2977
  }
2978

2979
  if (pEntryInfo->numOfRes == 0) {
60,014,300✔
2980
    colDataSetNULL(pCol, pBlock->info.rows);
2,348,546!
2981
    code = setNullSelectivityValue(pCtx, pBlock, pBlock->info.rows);
2,348,546✔
2982
  } else {
2983
    code = colDataSetVal(pCol, pBlock->info.rows, res, false);
57,665,754✔
2984
    if (TSDB_CODE_SUCCESS != code) {
57,453,239!
2985
      taosMemoryFree(res);
×
2986
      return code;
×
2987
    }
2988
    code = setSelectivityValue(pCtx, pBlock, &pRes->pos, pBlock->info.rows);
57,453,239✔
2989
  }
2990
  taosMemoryFree(res);
59,797,641✔
2991
  return code;
60,161,844✔
2992
}
2993

2994
int32_t lastCombine(SqlFunctionCtx* pDestCtx, SqlFunctionCtx* pSourceCtx) {
3✔
2995
  SResultRowEntryInfo* pDResInfo = GET_RES_INFO(pDestCtx);
3✔
2996
  SFirstLastRes*       pDBuf = GET_ROWCELL_INTERBUF(pDResInfo);
3✔
2997
  int32_t              bytes = pDBuf->bytes;
3✔
2998

2999
  SResultRowEntryInfo* pSResInfo = GET_RES_INFO(pSourceCtx);
3✔
3000
  SFirstLastRes*       pSBuf = GET_ROWCELL_INTERBUF(pSResInfo);
3✔
3001

3002
  pDBuf->hasResult = firstLastTransferInfoImpl(pSBuf, pDBuf, false);
3✔
3003
  pDResInfo->numOfRes = TMAX(pDResInfo->numOfRes, pSResInfo->numOfRes);
3✔
3004
  pDResInfo->isNullRes &= pSResInfo->isNullRes;
3✔
3005
  return TSDB_CODE_SUCCESS;
3✔
3006
}
3007

3008
static int32_t doSaveLastrow(SqlFunctionCtx* pCtx, char* pData, int32_t rowIndex, int64_t cts, SFirstLastRes* pInfo) {
39,751,746✔
3009
  SInputColumnInfoData* pInput = &pCtx->input;
39,751,746✔
3010
  SColumnInfoData*      pInputCol = pInput->pData[0];
39,751,746✔
3011
  SColumnInfoData*      pkCol = pInput->pPrimaryKey;
39,751,746✔
3012

3013
  if (colDataIsNull_s(pInputCol, rowIndex)) {
79,503,492✔
3014
    pInfo->isNull = true;
7,625✔
3015
  } else {
3016
    pInfo->isNull = false;
39,744,121✔
3017

3018
    if (IS_VAR_DATA_TYPE(pInputCol->info.type)) {
39,744,121!
3019
      if (pInputCol->info.type == TSDB_DATA_TYPE_JSON) {
3,152!
3020
        pInfo->bytes = getJsonValueLen(pData);
×
3021
      } else {
3022
        pInfo->bytes = varDataTLen(pData);
3,152✔
3023
      }
3024
    }
3025

3026
    (void)memcpy(pInfo->buf, pData, pInfo->bytes);
39,744,121✔
3027
  }
3028

3029
  if (pCtx->hasPrimaryKey && !colDataIsNull_s(pkCol, rowIndex)) {
39,751,819!
3030
    char* pkData = colDataGetData(pkCol, rowIndex);
73!
3031
    if (IS_VAR_DATA_TYPE(pInfo->pkType)) {
73!
3032
      if (pInfo->pkType == TSDB_DATA_TYPE_JSON) {
12!
3033
        pInfo->pkBytes = getJsonValueLen(pkData);
×
3034
      } else {
3035
        pInfo->pkBytes = varDataTLen(pkData);
12✔
3036
      }
3037
    }
3038
    (void)memcpy(pInfo->buf + pInfo->bytes, pkData, pInfo->pkBytes);
73✔
3039
    pInfo->pkData = pInfo->buf + pInfo->bytes;
73✔
3040
  }
3041
  pInfo->ts = cts;
39,751,746✔
3042
  int32_t code = firstlastSaveTupleData(pCtx->pSrcBlock, rowIndex, pCtx, pInfo, false);
39,751,746✔
3043
  if (code != TSDB_CODE_SUCCESS) {
39,746,557!
3044
    return code;
×
3045
  }
3046

3047
  pInfo->hasResult = true;
39,746,557✔
3048

3049
  return TSDB_CODE_SUCCESS;
39,746,557✔
3050
}
3051

3052
int32_t lastRowFunction(SqlFunctionCtx* pCtx) {
39,648,795✔
3053
  int32_t numOfElems = 0;
39,648,795✔
3054

3055
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
39,648,795✔
3056
  SFirstLastRes*       pInfo = GET_ROWCELL_INTERBUF(pResInfo);
39,648,795✔
3057

3058
  SInputColumnInfoData* pInput = &pCtx->input;
39,648,795✔
3059
  SColumnInfoData*      pInputCol = pInput->pData[0];
39,648,795✔
3060

3061
  int32_t type = pInputCol->info.type;
39,648,795✔
3062
  int32_t bytes = pInputCol->info.bytes;
39,648,795✔
3063
  pInfo->bytes = bytes;
39,648,795✔
3064

3065
  if (IS_NULL_TYPE(type)) {
39,648,795✔
3066
    return TSDB_CODE_SUCCESS;
56✔
3067
  }
3068
  SColumnInfoData* pkCol = pInput->pPrimaryKey;
39,648,739✔
3069
  pInfo->pkType = -1;
39,648,739✔
3070
  __compar_fn_t pkCompareFn = NULL;
39,648,739✔
3071
  if (pCtx->hasPrimaryKey) {
39,648,739✔
3072
    pInfo->pkType = pkCol->info.type;
57✔
3073
    pInfo->pkBytes = pkCol->info.bytes;
57✔
3074
    pkCompareFn = getKeyComparFunc(pInfo->pkType, TSDB_ORDER_DESC);
57✔
3075
  }
3076
  TSKEY startKey = getRowPTs(pInput->pPTS, 0);
39,651,764✔
3077
  TSKEY endKey = getRowPTs(pInput->pPTS, pInput->totalRows - 1);
39,651,764!
3078

3079
  if (pCtx->order == TSDB_ORDER_ASC && !pCtx->hasPrimaryKey) {
39,651,764!
3080
    for (int32_t i = pInput->numOfRows + pInput->startRowIndex - 1; i >= pInput->startRowIndex; --i) {
40,167,071!
3081
      bool  isNull = colDataIsNull(pInputCol, pInput->numOfRows, i, NULL);
20,084,884✔
3082
      char* data = isNull ? NULL : colDataGetData(pInputCol, i);
20,084,884!
3083
      TSKEY cts = getRowPTs(pInput->pPTS, i);
20,084,884!
3084
      numOfElems++;
20,084,884✔
3085

3086
      if (pResInfo->numOfRes == 0 || pInfo->ts < cts) {
20,084,884✔
3087
        int32_t code = doSaveLastrow(pCtx, data, i, cts, pInfo);
20,067,669✔
3088
        if (code != TSDB_CODE_SUCCESS) return code;
20,065,543!
3089
      }
3090

3091
      break;
20,082,758✔
3092
    }
3093
  } else if (!pCtx->hasPrimaryKey && pCtx->order == TSDB_ORDER_DESC) {
19,567,451!
3094
    // the optimized version only valid if all tuples in one block are monotonious increasing or descreasing.
3095
    // this assumption is NOT always works if project operator exists in downstream.
3096
    for (int32_t i = pInput->startRowIndex; i < pInput->numOfRows + pInput->startRowIndex; ++i) {
39,143,988!
3097
      bool  isNull = colDataIsNull(pInputCol, pInput->numOfRows, i, NULL);
19,572,934✔
3098
      char* data = isNull ? NULL : colDataGetData(pInputCol, i);
19,572,934!
3099
      TSKEY cts = getRowPTs(pInput->pPTS, i);
19,572,934!
3100
      numOfElems++;
19,572,934✔
3101

3102
      if (pResInfo->numOfRes == 0 || pInfo->ts < cts) {
19,572,934✔
3103
        int32_t code = doSaveLastrow(pCtx, data, i, cts, pInfo);
19,399,308✔
3104
        if (code != TSDB_CODE_SUCCESS) return code;
19,397,757!
3105
      }
3106
      break;
19,571,383✔
3107
    }
3108
  } else {
UNCOV
3109
    int64_t* pts = (int64_t*)pInput->pPTS->pData;
×
UNCOV
3110
    int      from = -1;
×
UNCOV
3111
    int32_t  i = -1;
×
3112
    while (funcInputGetNextRowIndex(pInput, from, false, &i, &from)) {
291,347✔
3113
      bool  isNull = colDataIsNull(pInputCol, pInput->numOfRows, i, NULL);
296,507✔
3114
      char* data = isNull ? NULL : colDataGetData(pInputCol, i);
296,507!
3115
      TSKEY cts = pts[i];
296,507✔
3116

3117
      numOfElems++;
296,507✔
3118
      char* pkData = NULL;
296,507✔
3119
      if (pCtx->hasPrimaryKey) {
296,507✔
3120
        pkData = colDataGetData(pkCol, i);
171!
3121
      }
3122
      if (pResInfo->numOfRes == 0 || pInfo->ts < cts ||
296,507✔
3123
          (pInfo->ts == pts[i] && pkCompareFn && pkCompareFn(pkData, pInfo->pkData) < 0)) {
9,832!
3124
        int32_t code = doSaveLastrow(pCtx, data, i, cts, pInfo);
286,681✔
3125
        if (code != TSDB_CODE_SUCCESS) {
286,675!
3126
          return code;
×
3127
        }
3128
        pResInfo->numOfRes = 1;
286,675✔
3129
      }
3130
    }
3131
  }
3132

3133
  SET_VAL(pResInfo, numOfElems, 1);
39,654,571!
3134
  return TSDB_CODE_SUCCESS;
39,654,571✔
3135
}
3136

3137
bool getDiffFuncEnv(SFunctionNode* UNUSED_PARAM(pFunc), SFuncExecEnv* pEnv) {
38,838✔
3138
  pEnv->calcMemSize = sizeof(SDiffInfo);
38,838✔
3139
  return true;
38,838✔
3140
}
3141

3142
int32_t diffFunctionSetup(SqlFunctionCtx* pCtx, SResultRowEntryInfo* pResInfo) {
1,990,660✔
3143
  if (pResInfo->initialized) {
1,990,660✔
3144
    return TSDB_CODE_SUCCESS;
1,899,689✔
3145
  }
3146
  if (TSDB_CODE_SUCCESS != functionSetup(pCtx, pResInfo)) {
90,971!
3147
    return TSDB_CODE_FUNC_SETUP_ERROR;
×
3148
  }
3149
  SDiffInfo* pDiffInfo = GET_ROWCELL_INTERBUF(pResInfo);
90,971✔
3150
  pDiffInfo->hasPrev = false;
90,971✔
3151
  pDiffInfo->isFirstRow = true;
90,971✔
3152
  pDiffInfo->prev.i64 = 0;
90,971✔
3153
  pDiffInfo->prevTs = -1;
90,971✔
3154
  if (pCtx->numOfParams > 1) {
90,971!
3155
    pDiffInfo->ignoreOption = pCtx->param[1].param.i;  // TODO set correct param
90,971✔
3156
  } else {
3157
    pDiffInfo->ignoreOption = 0;
×
3158
  }
3159
  return TSDB_CODE_SUCCESS;
90,971✔
3160
}
3161

3162
static int32_t doSetPrevVal(SDiffInfo* pDiffInfo, int32_t type, const char* pv, int64_t ts) {
1,646,740✔
3163
  switch (type) {
1,646,740!
3164
    case TSDB_DATA_TYPE_BOOL:
28✔
3165
      pDiffInfo->prev.i64 = *(bool*)pv ? 1 : 0;
28✔
3166
      break;
28✔
3167
    case TSDB_DATA_TYPE_UTINYINT:
303✔
3168
    case TSDB_DATA_TYPE_TINYINT:
3169
      pDiffInfo->prev.i64 = *(int8_t*)pv;
303✔
3170
      break;
303✔
3171
    case TSDB_DATA_TYPE_UINT:
53,364✔
3172
    case TSDB_DATA_TYPE_INT:
3173
      pDiffInfo->prev.i64 = *(int32_t*)pv;
53,364✔
3174
      break;
53,364✔
3175
    case TSDB_DATA_TYPE_USMALLINT:
1,230,403✔
3176
    case TSDB_DATA_TYPE_SMALLINT:
3177
      pDiffInfo->prev.i64 = *(int16_t*)pv;
1,230,403✔
3178
      break;
1,230,403✔
3179
    case TSDB_DATA_TYPE_TIMESTAMP:
313✔
3180
    case TSDB_DATA_TYPE_UBIGINT:
3181
    case TSDB_DATA_TYPE_BIGINT:
3182
      pDiffInfo->prev.i64 = *(int64_t*)pv;
313✔
3183
      break;
313✔
3184
    case TSDB_DATA_TYPE_FLOAT:
233✔
3185
      pDiffInfo->prev.d64 = *(float*)pv;
233✔
3186
      break;
233✔
3187
    case TSDB_DATA_TYPE_DOUBLE:
362,096✔
3188
      pDiffInfo->prev.d64 = *(double*)pv;
362,096✔
3189
      break;
362,096✔
3190
    default:
×
3191
      return TSDB_CODE_FUNC_FUNTION_PARA_TYPE;
×
3192
  }
3193
  pDiffInfo->prevTs = ts;
1,646,740✔
3194
  pDiffInfo->hasPrev = true;
1,646,740✔
3195
  return TSDB_CODE_SUCCESS;
1,646,740✔
3196
}
3197

3198
static bool diffIsNegtive(SDiffInfo* pDiffInfo, int32_t type, const char* pv) {
7,375,027✔
3199
  switch (type) {
7,375,027!
3200
    case TSDB_DATA_TYPE_UINT: {
×
3201
      int64_t v = *(uint32_t*)pv;
×
3202
      return v < pDiffInfo->prev.i64;
×
3203
    }
3204
    case TSDB_DATA_TYPE_INT: {
2,330✔
3205
      int64_t v = *(int32_t*)pv;
2,330✔
3206
      return v < pDiffInfo->prev.i64;
2,330✔
3207
    }
3208
    case TSDB_DATA_TYPE_BOOL: {
×
3209
      int64_t v = *(bool*)pv;
×
3210
      return v < pDiffInfo->prev.i64;
×
3211
    }
3212
    case TSDB_DATA_TYPE_UTINYINT: {
×
3213
      int64_t v = *(uint8_t*)pv;
×
3214
      return v < pDiffInfo->prev.i64;
×
3215
    }
3216
    case TSDB_DATA_TYPE_TINYINT: {
3,072✔
3217
      int64_t v = *(int8_t*)pv;
3,072✔
3218
      return v < pDiffInfo->prev.i64;
3,072✔
3219
    }
3220
    case TSDB_DATA_TYPE_USMALLINT: {
×
3221
      int64_t v = *(uint16_t*)pv;
×
3222
      return v < pDiffInfo->prev.i64;
×
3223
    }
3224
    case TSDB_DATA_TYPE_SMALLINT: {
6,098,624✔
3225
      int64_t v = *(int16_t*)pv;
6,098,624✔
3226
      return v < pDiffInfo->prev.i64;
6,098,624✔
3227
    }
3228
    case TSDB_DATA_TYPE_UBIGINT: {
24✔
3229
      uint64_t v = *(uint64_t*)pv;
24✔
3230
      return v < (uint64_t)pDiffInfo->prev.i64;
24✔
3231
    }
3232
    case TSDB_DATA_TYPE_TIMESTAMP:
6,312✔
3233
    case TSDB_DATA_TYPE_BIGINT: {
3234
      int64_t v = *(int64_t*)pv;
6,312✔
3235
      return v < pDiffInfo->prev.i64;
6,312✔
3236
    }
3237
    case TSDB_DATA_TYPE_FLOAT: {
3,792✔
3238
      float v = *(float*)pv;
3,792✔
3239
      return v < pDiffInfo->prev.d64;
3,792✔
3240
    }
3241
    case TSDB_DATA_TYPE_DOUBLE: {
1,260,873✔
3242
      double v = *(double*)pv;
1,260,873✔
3243
      return v < pDiffInfo->prev.d64;
1,260,873✔
3244
    }
3245
    default:
×
3246
      return false;
×
3247
  }
3248

3249
  return false;
3250
}
3251

3252
static void tryToSetInt64(SDiffInfo* pDiffInfo, int32_t type, SColumnInfoData* pOutput, int64_t v, int32_t pos) {
1,603,736,892✔
3253
  bool isNegative = v < pDiffInfo->prev.i64;
1,603,736,892✔
3254
  if (type == TSDB_DATA_TYPE_UBIGINT) {
1,603,736,892✔
3255
    isNegative = (uint64_t)v < (uint64_t)pDiffInfo->prev.i64;
453✔
3256
  }
3257
  int64_t delta = v - pDiffInfo->prev.i64;
1,603,736,892✔
3258
  if (isNegative && ignoreNegative(pDiffInfo->ignoreOption)) {
1,603,736,892✔
3259
    colDataSetNull_f_s(pOutput, pos);
1,912,809✔
3260
    pOutput->hasNull = true;
1,912,809✔
3261
  } else {
3262
    colDataSetInt64(pOutput, pos, &delta);
1,601,824,083✔
3263
  }
3264
  pDiffInfo->prev.i64 = v;
1,603,736,892✔
3265
}
1,603,736,892✔
3266

3267
static void tryToSetDouble(SDiffInfo* pDiffInfo, SColumnInfoData* pOutput, double v, int32_t pos) {
1,411,724✔
3268
  double delta = v - pDiffInfo->prev.d64;
1,411,724✔
3269
  if (delta < 0 && ignoreNegative(pDiffInfo->ignoreOption)) {
1,411,724✔
3270
    colDataSetNull_f_s(pOutput, pos);
291,069✔
3271
  } else {
3272
    colDataSetDouble(pOutput, pos, &delta);
1,120,655✔
3273
  }
3274
  pDiffInfo->prev.d64 = v;
1,411,724✔
3275
}
1,411,724✔
3276

3277
static int32_t doHandleDiff(SDiffInfo* pDiffInfo, int32_t type, const char* pv, SColumnInfoData* pOutput, int32_t pos,
1,605,149,185✔
3278
                            int64_t ts) {
3279
  if (!pDiffInfo->hasPrev) {
1,605,149,185✔
3280
    colDataSetNull_f_s(pOutput, pos);
569✔
3281
    return doSetPrevVal(pDiffInfo, type, pv, ts);
569✔
3282
  }
3283
  pDiffInfo->prevTs = ts;
1,605,148,616✔
3284
  switch (type) {
1,605,148,616!
3285
    case TSDB_DATA_TYPE_UINT: {
411✔
3286
      int64_t v = *(uint32_t*)pv;
411✔
3287
      tryToSetInt64(pDiffInfo, type, pOutput, v, pos);
411✔
3288
      break;
411✔
3289
    }
3290
    case TSDB_DATA_TYPE_INT: {
26,248,971✔
3291
      int64_t v = *(int32_t*)pv;
26,248,971✔
3292
      tryToSetInt64(pDiffInfo, type, pOutput, v, pos);
26,248,971✔
3293
      break;
26,248,971✔
3294
    }
3295
    case TSDB_DATA_TYPE_BOOL: {
10,617✔
3296
      int64_t v = *(bool*)pv;
10,617✔
3297
      tryToSetInt64(pDiffInfo, type, pOutput, v, pos);
10,617✔
3298
      break;
10,617✔
3299
    }
3300
    case TSDB_DATA_TYPE_UTINYINT: {
405✔
3301
      int64_t v = *(uint8_t*)pv;
405✔
3302
      tryToSetInt64(pDiffInfo, type, pOutput, v, pos);
405✔
3303
      break;
405✔
3304
    }
3305
    case TSDB_DATA_TYPE_TINYINT: {
35,711✔
3306
      int64_t v = *(int8_t*)pv;
35,711✔
3307
      tryToSetInt64(pDiffInfo, type, pOutput, v, pos);
35,711✔
3308
      break;
35,711✔
3309
    }
3310
    case TSDB_DATA_TYPE_USMALLINT: {
405✔
3311
      int64_t v = *(uint16_t*)pv;
405✔
3312
      tryToSetInt64(pDiffInfo, type, pOutput, v, pos);
405✔
3313
      break;
405✔
3314
    }
3315
    case TSDB_DATA_TYPE_SMALLINT: {
5,899,787✔
3316
      int64_t v = *(int16_t*)pv;
5,899,787✔
3317
      tryToSetInt64(pDiffInfo, type, pOutput, v, pos);
5,899,787✔
3318
      break;
5,899,787✔
3319
    }
3320
    case TSDB_DATA_TYPE_TIMESTAMP:
1,571,540,585✔
3321
    case TSDB_DATA_TYPE_UBIGINT:
3322
    case TSDB_DATA_TYPE_BIGINT: {
3323
      int64_t v = *(int64_t*)pv;
1,571,540,585✔
3324
      tryToSetInt64(pDiffInfo, type, pOutput, v, pos);
1,571,540,585✔
3325
      break;
1,571,540,585✔
3326
    }
3327
    case TSDB_DATA_TYPE_FLOAT: {
45,744✔
3328
      double v = *(float*)pv;
45,744✔
3329
      tryToSetDouble(pDiffInfo, pOutput, v, pos);
45,744✔
3330
      break;
45,744✔
3331
    }
3332
    case TSDB_DATA_TYPE_DOUBLE: {
1,365,980✔
3333
      double v = *(double*)pv;
1,365,980✔
3334
      tryToSetDouble(pDiffInfo, pOutput, v, pos);
1,365,980✔
3335
      break;
1,365,980✔
3336
    }
3337
    default:
×
3338
      return TSDB_CODE_FUNC_FUNTION_PARA_TYPE;
×
3339
  }
3340
  pDiffInfo->hasPrev = true;
1,605,148,616✔
3341
  return TSDB_CODE_SUCCESS;
1,605,148,616✔
3342
}
3343

3344
// TODO: the primary key compare can be skipped for ordered pk if knonwn before
3345
// TODO: for desc ordered, pk shall select the smallest one for one ts. if across block boundaries.
3346
bool funcInputGetNextRowIndex(SInputColumnInfoData* pInput, int32_t from, bool firstOccur, int32_t* pRowIndex,
304,138,425✔
3347
                              int32_t* nextFrom) {
3348
  if (pInput->pPrimaryKey == NULL) {
304,138,425✔
3349
    if (from == -1) {
204,169,813✔
3350
      from = pInput->startRowIndex;
66,635,574✔
3351
    } else if (from >= pInput->numOfRows + pInput->startRowIndex) {
137,534,239✔
3352
      return false;
66,382,060✔
3353
    }
3354
    *pRowIndex = from;
137,787,753✔
3355
    *nextFrom = from + 1;
137,787,753✔
3356
    return true;
137,787,753✔
3357
  } else {
3358
    if (from == -1) {
99,968,612✔
3359
      from = pInput->startRowIndex;
30,175✔
3360
    } else if (from >= pInput->numOfRows + pInput->startRowIndex) {
99,938,437✔
3361
      return false;
30,175✔
3362
    }
3363
    TSKEY*           tsList = (int64_t*)pInput->pPTS->pData;
99,938,437✔
3364
    SColumnInfoData* pkCol = pInput->pPrimaryKey;
99,938,437✔
3365
    int8_t           pkType = pkCol->info.type;
99,938,437✔
3366
    int32_t          order = (firstOccur) ? TSDB_ORDER_ASC : TSDB_ORDER_DESC;
99,938,437✔
3367
    __compar_fn_t    compareFunc = getKeyComparFunc(pkType, order);
99,938,437✔
3368
    int32_t          select = from;
100,000,517✔
3369
    char*            val = colDataGetData(pkCol, select);
100,000,517!
3370
    while (from < pInput->numOfRows + pInput->startRowIndex - 1 && tsList[from + 1] == tsList[from]) {
100,001,072✔
3371
      char* val1 = colDataGetData(pkCol, from + 1);
555!
3372
      if (compareFunc(val1, val) < 0) {
555!
3373
        select = from + 1;
×
3374
        val = val1;
×
3375
      }
3376
      from = from + 1;
555✔
3377
    }
3378
    *pRowIndex = select;
100,000,517✔
3379
    *nextFrom = from + 1;
100,000,517✔
3380
    return true;
100,000,517✔
3381
  }
3382
}
3383

3384
bool getForecastConfEnv(SFunctionNode* UNUSED_PARAM(pFunc), SFuncExecEnv* pEnv) {
26✔
3385
  pEnv->calcMemSize = sizeof(float);
26✔
3386
  return true;
26✔
3387
}
3388

3389
int32_t diffResultIsNull(SqlFunctionCtx* pCtx, SFuncInputRow* pRow) {
1,606,889,799✔
3390
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
1,606,889,799✔
3391
  SDiffInfo*           pDiffInfo = GET_ROWCELL_INTERBUF(pResInfo);
1,606,889,799✔
3392

3393
  if (pRow->isDataNull || !pDiffInfo->hasPrev) {
1,606,889,799✔
3394
    return true;
184,222✔
3395
  } else if (ignoreNegative(pDiffInfo->ignoreOption)) {
1,606,705,577✔
3396
    return diffIsNegtive(pDiffInfo, pCtx->input.pData[0]->info.type, pRow->pData);
7,375,027✔
3397
  }
3398
  return false;
1,599,330,550✔
3399
}
3400

3401
bool isFirstRow(SqlFunctionCtx* pCtx, SFuncInputRow* pRow) {
1,605,319,571✔
3402
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
1,605,319,571✔
3403
  SDiffInfo*           pDiffInfo = GET_ROWCELL_INTERBUF(pResInfo);
1,605,319,571✔
3404
  return pDiffInfo->isFirstRow;
1,605,319,571✔
3405
}
3406

3407
int32_t trySetPreVal(SqlFunctionCtx* pCtx, SFuncInputRow* pRow) {
1,647,969✔
3408
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
1,647,969✔
3409
  SDiffInfo*           pDiffInfo = GET_ROWCELL_INTERBUF(pResInfo);
1,647,969✔
3410
  pDiffInfo->isFirstRow = false;
1,647,969✔
3411
  if (pRow->isDataNull) {
1,647,969✔
3412
    return TSDB_CODE_SUCCESS;
1,798✔
3413
  }
3414

3415
  SInputColumnInfoData* pInput = &pCtx->input;
1,646,171✔
3416
  SColumnInfoData*      pInputCol = pInput->pData[0];
1,646,171✔
3417
  int8_t                inputType = pInputCol->info.type;
1,646,171✔
3418

3419
  char* pv = pRow->pData;
1,646,171✔
3420
  return doSetPrevVal(pDiffInfo, inputType, pv, pRow->ts);
1,646,171✔
3421
}
3422

3423
int32_t setDoDiffResult(SqlFunctionCtx* pCtx, SFuncInputRow* pRow, int32_t pos) {
1,605,241,830✔
3424
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
1,605,241,830✔
3425
  SDiffInfo*           pDiffInfo = GET_ROWCELL_INTERBUF(pResInfo);
1,605,241,830✔
3426

3427
  SInputColumnInfoData* pInput = &pCtx->input;
1,605,241,830✔
3428
  SColumnInfoData*      pInputCol = pInput->pData[0];
1,605,241,830✔
3429
  int8_t                inputType = pInputCol->info.type;
1,605,241,830✔
3430
  SColumnInfoData*      pOutput = (SColumnInfoData*)pCtx->pOutput;
1,605,241,830✔
3431
  int32_t               code = TSDB_CODE_SUCCESS;
1,605,241,830✔
3432
  if (pRow->isDataNull) {
1,605,241,830✔
3433
    colDataSetNull_f_s(pOutput, pos);
92,624✔
3434
    pOutput->hasNull = true;
92,624✔
3435

3436
    // handle selectivity
3437
    if (pCtx->subsidiaries.num > 0) {
92,624✔
3438
      code = appendSelectivityCols(pCtx, pRow->block, pRow->rowIndex, pos);
149✔
3439
      if (code != TSDB_CODE_SUCCESS) {
149!
3440
        return code;
×
3441
      }
3442
    }
3443
    return TSDB_CODE_SUCCESS;
92,624✔
3444
  }
3445

3446
  char* pv = pRow->pData;
1,605,149,206✔
3447

3448
  if (pRow->ts == pDiffInfo->prevTs) {
1,605,149,206✔
3449
    return TSDB_CODE_FUNC_DUP_TIMESTAMP;
21✔
3450
  }
3451
  code = doHandleDiff(pDiffInfo, inputType, pv, pOutput, pos, pRow->ts);
1,605,149,185✔
3452
  if (code != TSDB_CODE_SUCCESS) {
1,605,149,185!
3453
    return code;
×
3454
  }
3455
  // handle selectivity
3456
  if (pCtx->subsidiaries.num > 0) {
1,605,149,185✔
3457
    code = appendSelectivityCols(pCtx, pRow->block, pRow->rowIndex, pos);
34,009,307✔
3458
    if (code != TSDB_CODE_SUCCESS) {
34,009,307!
3459
      return code;
×
3460
    }
3461
  }
3462

3463
  return TSDB_CODE_SUCCESS;
1,605,149,185✔
3464
}
3465

3466
int32_t diffFunction(SqlFunctionCtx* pCtx) { return TSDB_CODE_SUCCESS; }
1,951,822✔
3467

3468
int32_t diffFunctionByRow(SArray* pCtxArray) {
1,951,666✔
3469
  int32_t code = TSDB_CODE_SUCCESS;
1,951,666✔
3470
  int     diffColNum = pCtxArray->size;
1,951,666✔
3471
  if (diffColNum == 0) {
1,951,666!
3472
    return TSDB_CODE_SUCCESS;
×
3473
  }
3474
  int32_t numOfElems = 0;
1,951,666✔
3475

3476
  SArray* pRows = taosArrayInit_s(sizeof(SFuncInputRow), diffColNum);
1,951,666✔
3477
  if (NULL == pRows) {
1,951,666!
3478
    return terrno;
×
3479
  }
3480

3481
  bool keepNull = false;
1,951,666✔
3482
  for (int i = 0; i < diffColNum; ++i) {
3,903,488✔
3483
    SqlFunctionCtx* pCtx = *(SqlFunctionCtx**)taosArrayGet(pCtxArray, i);
1,951,822✔
3484
    if (NULL == pCtx) {
1,951,822!
3485
      code = terrno;
×
3486
      goto _exit;
×
3487
    }
3488
    funcInputUpdate(pCtx);
1,951,822✔
3489
    SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
1,951,822✔
3490
    SDiffInfo*           pDiffInfo = GET_ROWCELL_INTERBUF(pResInfo);
1,951,822✔
3491
    if (!ignoreNull(pDiffInfo->ignoreOption)) {
1,951,822✔
3492
      keepNull = true;
1,932,801✔
3493
    }
3494
  }
3495

3496
  SqlFunctionCtx* pCtx0 = *(SqlFunctionCtx**)taosArrayGet(pCtxArray, 0);
1,951,666✔
3497
  SFuncInputRow*  pRow0 = (SFuncInputRow*)taosArrayGet(pRows, 0);
1,951,666✔
3498
  if (NULL == pCtx0 || NULL == pRow0) {
1,951,666!
3499
    code = terrno;
×
3500
    goto _exit;
×
3501
  }
3502
  int32_t startOffset = pCtx0->offset;
1,951,666✔
3503
  bool    result = false;
1,951,666✔
3504
  while (1) {
1,606,875,284✔
3505
    code = funcInputGetNextRow(pCtx0, pRow0, &result);
1,608,826,950✔
3506
    if (TSDB_CODE_SUCCESS != code) {
1,608,826,950!
3507
      goto _exit;
×
3508
    }
3509
    if (!result) {
1,608,826,950✔
3510
      break;
1,951,645✔
3511
    }
3512
    bool hasNotNullValue = !diffResultIsNull(pCtx0, pRow0);
1,606,875,305✔
3513
    for (int i = 1; i < diffColNum; ++i) {
1,606,889,799✔
3514
      SqlFunctionCtx* pCtx = *(SqlFunctionCtx**)taosArrayGet(pCtxArray, i);
14,494✔
3515
      SFuncInputRow*  pRow = (SFuncInputRow*)taosArrayGet(pRows, i);
14,494✔
3516
      if (NULL == pCtx || NULL == pRow) {
14,494!
3517
        code = terrno;
×
3518
        goto _exit;
×
3519
      }
3520
      code = funcInputGetNextRow(pCtx, pRow, &result);
14,494✔
3521
      if (TSDB_CODE_SUCCESS != code) {
14,494!
3522
        goto _exit;
×
3523
      }
3524
      if (!result) {
14,494!
3525
        // rows are not equal
3526
        code = TSDB_CODE_QRY_EXECUTOR_INTERNAL_ERROR;
×
3527
        goto _exit;
×
3528
      }
3529
      if (!diffResultIsNull(pCtx, pRow)) {
14,494✔
3530
        hasNotNullValue = true;
14,052✔
3531
      }
3532
    }
3533
    int32_t pos = startOffset + numOfElems;
1,606,875,305✔
3534

3535
    bool newRow = false;
1,606,875,305✔
3536
    for (int i = 0; i < diffColNum; ++i) {
2,147,483,647✔
3537
      SqlFunctionCtx* pCtx = *(SqlFunctionCtx**)taosArrayGet(pCtxArray, i);
1,606,889,799✔
3538
      SFuncInputRow*  pRow = (SFuncInputRow*)taosArrayGet(pRows, i);
1,606,889,799✔
3539
      if (NULL == pCtx || NULL == pRow) {
1,606,889,799!
3540
        code = terrno;
×
3541
        goto _exit;
×
3542
      }
3543
      if ((keepNull || hasNotNullValue) && !isFirstRow(pCtx, pRow)) {
1,606,889,799✔
3544
        code = setDoDiffResult(pCtx, pRow, pos);
1,605,241,830✔
3545
        if (code != TSDB_CODE_SUCCESS) {
1,605,241,830✔
3546
          goto _exit;
21✔
3547
        }
3548
        newRow = true;
1,605,241,809✔
3549
      } else {
3550
        code = trySetPreVal(pCtx, pRow);
1,647,969✔
3551
        if (code != TSDB_CODE_SUCCESS) {
1,647,969!
3552
          goto _exit;
×
3553
        }
3554
      }
3555
    }
3556
    if (newRow) ++numOfElems;
1,606,875,284✔
3557
  }
3558

3559
  for (int i = 0; i < diffColNum; ++i) {
3,903,443✔
3560
    SqlFunctionCtx* pCtx = *(SqlFunctionCtx**)taosArrayGet(pCtxArray, i);
1,951,798✔
3561
    if (NULL == pCtx) {
1,951,798!
3562
      code = terrno;
×
3563
      goto _exit;
×
3564
    }
3565
    SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
1,951,798✔
3566
    pResInfo->numOfRes = numOfElems;
1,951,798✔
3567
  }
3568

3569
_exit:
1,951,645✔
3570
  if (pRows) {
1,951,666!
3571
    taosArrayDestroy(pRows);
1,951,666✔
3572
    pRows = NULL;
1,951,666✔
3573
  }
3574
  return code;
1,951,666✔
3575
}
3576

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

3579
bool getTopBotFuncEnv(SFunctionNode* pFunc, SFuncExecEnv* pEnv) {
87,283✔
3580
  SValueNode* pkNode = (SValueNode*)nodesListGetNode(pFunc->pParameterList, 1);
87,283✔
3581
  pEnv->calcMemSize = sizeof(STopBotRes) + pkNode->datum.i * sizeof(STopBotResItem);
87,345✔
3582
  return true;
87,345✔
3583
}
3584

3585
int32_t topBotFunctionSetup(SqlFunctionCtx* pCtx, SResultRowEntryInfo* pResInfo) {
46,102,291✔
3586
  if (pResInfo->initialized) {
46,102,291!
3587
    return TSDB_CODE_SUCCESS;
×
3588
  }
3589
  if (TSDB_CODE_SUCCESS != functionSetup(pCtx, pResInfo)) {
46,102,291!
3590
    return TSDB_CODE_FUNC_SETUP_ERROR;
×
3591
  }
3592

3593
  STopBotRes*           pRes = GET_ROWCELL_INTERBUF(pResInfo);
46,130,480✔
3594
  SInputColumnInfoData* pInput = &pCtx->input;
46,130,480✔
3595

3596
  pRes->maxSize = pCtx->param[1].param.i;
46,130,480✔
3597

3598
  pRes->nullTupleSaved = false;
46,130,480✔
3599
  pRes->nullTuplePos.pageId = -1;
46,130,480✔
3600
  return TSDB_CODE_SUCCESS;
46,130,480✔
3601
}
3602

3603
static STopBotRes* getTopBotOutputInfo(SqlFunctionCtx* pCtx) {
211,719,539✔
3604
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
211,719,539✔
3605
  STopBotRes*          pRes = GET_ROWCELL_INTERBUF(pResInfo);
211,719,539✔
3606
  pRes->pItems = (STopBotResItem*)((char*)pRes + sizeof(STopBotRes));
211,719,539✔
3607

3608
  return pRes;
211,719,539✔
3609
}
3610

3611
static int32_t doAddIntoResult(SqlFunctionCtx* pCtx, void* pData, int32_t rowIndex, SSDataBlock* pSrcBlock,
3612
                               uint16_t type, uint64_t uid, SResultRowEntryInfo* pEntryInfo, bool isTopQuery);
3613

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

3616
int32_t topFunction(SqlFunctionCtx* pCtx) {
14,749,893✔
3617
  int32_t              numOfElems = 0;
14,749,893✔
3618
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
14,749,893✔
3619

3620
  SInputColumnInfoData* pInput = &pCtx->input;
14,749,893✔
3621
  SColumnInfoData*      pCol = pInput->pData[0];
14,749,893✔
3622

3623
  STopBotRes* pRes = getTopBotOutputInfo(pCtx);
14,749,893✔
3624
  pRes->type = pInput->pData[0]->info.type;
14,749,894✔
3625

3626
  int32_t start = pInput->startRowIndex;
14,749,894✔
3627
  for (int32_t i = start; i < pInput->numOfRows + start; ++i) {
47,936,135✔
3628
    if (pCol->hasNull && colDataIsNull_f(pCol->nullbitmap, i)) {
33,185,108✔
3629
      continue;
22,680✔
3630
    }
3631

3632
    numOfElems++;
33,162,428✔
3633
    char*   data = colDataGetData(pCol, i);
33,162,428!
3634
    int32_t code = doAddIntoResult(pCtx, data, i, pCtx->pSrcBlock, pRes->type, pInput->uid, pResInfo, true);
33,162,428✔
3635
    if (code != TSDB_CODE_SUCCESS) {
33,163,561!
3636
      return code;
×
3637
    }
3638
  }
3639

3640
  if (numOfElems == 0 && pCtx->subsidiaries.num > 0 && !pRes->nullTupleSaved) {
14,751,027✔
3641
    int32_t code = saveTupleData(pCtx, pInput->startRowIndex, pCtx->pSrcBlock, &pRes->nullTuplePos);
99✔
3642
    if (code != TSDB_CODE_SUCCESS) {
99!
3643
      return code;
×
3644
    }
3645
    pRes->nullTupleSaved = true;
99✔
3646
  }
3647
  return TSDB_CODE_SUCCESS;
14,751,027✔
3648
}
3649

3650
int32_t bottomFunction(SqlFunctionCtx* pCtx) {
32,406,222✔
3651
  int32_t              numOfElems = 0;
32,406,222✔
3652
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
32,406,222✔
3653

3654
  SInputColumnInfoData* pInput = &pCtx->input;
32,406,222✔
3655
  SColumnInfoData*      pCol = pInput->pData[0];
32,406,222✔
3656

3657
  STopBotRes* pRes = getTopBotOutputInfo(pCtx);
32,406,222✔
3658
  pRes->type = pInput->pData[0]->info.type;
32,405,813✔
3659

3660
  int32_t start = pInput->startRowIndex;
32,405,813✔
3661
  for (int32_t i = start; i < pInput->numOfRows + start; ++i) {
118,229,969✔
3662
    if (pCol->hasNull && colDataIsNull_f(pCol->nullbitmap, i)) {
85,774,604✔
3663
      continue;
24,354✔
3664
    }
3665

3666
    numOfElems++;
85,750,250✔
3667
    char*   data = colDataGetData(pCol, i);
85,750,250!
3668
    int32_t code = doAddIntoResult(pCtx, data, i, pCtx->pSrcBlock, pRes->type, pInput->uid, pResInfo, false);
85,750,250✔
3669
    if (code != TSDB_CODE_SUCCESS) {
85,799,802!
3670
      return code;
×
3671
    }
3672
  }
3673

3674
  if (numOfElems == 0 && pCtx->subsidiaries.num > 0 && !pRes->nullTupleSaved) {
32,455,365✔
3675
    int32_t code = saveTupleData(pCtx, pInput->startRowIndex, pCtx->pSrcBlock, &pRes->nullTuplePos);
5,201✔
3676
    if (code != TSDB_CODE_SUCCESS) {
5,201!
3677
      return code;
×
3678
    }
3679
    pRes->nullTupleSaved = true;
5,201✔
3680
  }
3681

3682
  return TSDB_CODE_SUCCESS;
32,455,365✔
3683
}
3684

3685
static int32_t topBotResComparFn(const void* p1, const void* p2, const void* param) {
309,403,307✔
3686
  uint16_t type = *(uint16_t*)param;
309,403,307✔
3687

3688
  STopBotResItem* val1 = (STopBotResItem*)p1;
309,403,307✔
3689
  STopBotResItem* val2 = (STopBotResItem*)p2;
309,403,307✔
3690

3691
  if (IS_SIGNED_NUMERIC_TYPE(type)) {
309,403,307!
3692
    if (val1->v.i == val2->v.i) {
247,470,186✔
3693
      return 0;
201,845✔
3694
    }
3695

3696
    return (val1->v.i > val2->v.i) ? 1 : -1;
247,268,341✔
3697
  } else if (IS_UNSIGNED_NUMERIC_TYPE(type)) {
61,933,121!
3698
    if (val1->v.u == val2->v.u) {
645,631✔
3699
      return 0;
140,346✔
3700
    }
3701

3702
    return (val1->v.u > val2->v.u) ? 1 : -1;
505,285✔
3703
  } else if (TSDB_DATA_TYPE_FLOAT == type) {
61,287,490✔
3704
    if (val1->v.f == val2->v.f) {
38,472,117✔
3705
      return 0;
63✔
3706
    }
3707

3708
    return (val1->v.f > val2->v.f) ? 1 : -1;
38,472,054✔
3709
  }
3710

3711
  if (val1->v.d == val2->v.d) {
22,815,373✔
3712
    return 0;
11✔
3713
  }
3714

3715
  return (val1->v.d > val2->v.d) ? 1 : -1;
22,815,362✔
3716
}
3717

3718
int32_t doAddIntoResult(SqlFunctionCtx* pCtx, void* pData, int32_t rowIndex, SSDataBlock* pSrcBlock, uint16_t type,
118,869,628✔
3719
                        uint64_t uid, SResultRowEntryInfo* pEntryInfo, bool isTopQuery) {
3720
  STopBotRes* pRes = getTopBotOutputInfo(pCtx);
118,869,628✔
3721
  int32_t     code = TSDB_CODE_SUCCESS;
118,848,104✔
3722

3723
  SVariant val = {0};
118,848,104✔
3724
  TAOS_CHECK_RETURN(taosVariantCreateFromBinary(&val, pData, tDataTypes[type].bytes, type));
118,848,104!
3725

3726
  STopBotResItem* pItems = pRes->pItems;
118,939,973✔
3727

3728
  // not full yet
3729
  if (pEntryInfo->numOfRes < pRes->maxSize) {
118,939,973✔
3730
    STopBotResItem* pItem = &pItems[pEntryInfo->numOfRes];
75,078,045✔
3731
    pItem->v = val;
75,078,045✔
3732
    pItem->uid = uid;
75,078,045✔
3733

3734
    // save the data of this tuple
3735
    if (pCtx->subsidiaries.num > 0) {
75,078,045✔
3736
      code = saveTupleData(pCtx, rowIndex, pSrcBlock, &pItem->tuplePos);
49,544,833✔
3737
      if (code != TSDB_CODE_SUCCESS) {
49,375,874!
3738
        return code;
×
3739
      }
3740
    }
3741
#ifdef BUF_PAGE_DEBUG
3742
    qDebug("page_saveTuple i:%d, item:%p,pageId:%d, offset:%d\n", pEntryInfo->numOfRes, pItem, pItem->tuplePos.pageId,
3743
           pItem->tuplePos.offset);
3744
#endif
3745
    // allocate the buffer and keep the data of this row into the new allocated buffer
3746
    pEntryInfo->numOfRes++;
74,909,086✔
3747
    code = taosheapsort((void*)pItems, sizeof(STopBotResItem), pEntryInfo->numOfRes, (const void*)&type,
74,909,086✔
3748
                        topBotResComparFn, !isTopQuery);
74,909,086✔
3749
    if (code != TSDB_CODE_SUCCESS) {
75,129,406!
3750
      return code;
×
3751
    }
3752
  } else {  // replace the minimum value in the result
3753
    if ((isTopQuery && ((IS_SIGNED_NUMERIC_TYPE(type) && val.i > pItems[0].v.i) ||
43,861,928!
3754
                        (IS_UNSIGNED_NUMERIC_TYPE(type) && val.u > pItems[0].v.u) ||
8,426,480✔
3755
                        (TSDB_DATA_TYPE_FLOAT == type && val.f > pItems[0].v.f) ||
8,335,678✔
3756
                        (TSDB_DATA_TYPE_DOUBLE == type && val.d > pItems[0].v.d))) ||
7,821,292✔
3757
        (!isTopQuery && ((IS_SIGNED_NUMERIC_TYPE(type) && val.i < pItems[0].v.i) ||
40,777,161!
3758
                         (IS_UNSIGNED_NUMERIC_TYPE(type) && val.u < pItems[0].v.u) ||
28,383,244!
3759
                         (TSDB_DATA_TYPE_FLOAT == type && val.f < pItems[0].v.f) ||
28,382,254✔
3760
                         (TSDB_DATA_TYPE_DOUBLE == type && val.d < pItems[0].v.d)))) {
28,229,671✔
3761
      // replace the old data and the coresponding tuple data
3762
      STopBotResItem* pItem = &pItems[0];
8,787,631✔
3763
      pItem->v = val;
8,787,631✔
3764
      pItem->uid = uid;
8,787,631✔
3765

3766
      // save the data of this tuple by over writing the old data
3767
      if (pCtx->subsidiaries.num > 0) {
8,787,631✔
3768
        code = updateTupleData(pCtx, rowIndex, pSrcBlock, &pItem->tuplePos);
6,643,943✔
3769
        if (code != TSDB_CODE_SUCCESS) {
6,636,431!
3770
          return code;
×
3771
        }
3772
      }
3773
#ifdef BUF_PAGE_DEBUG
3774
      qDebug("page_copyTuple pageId:%d, offset:%d", pItem->tuplePos.pageId, pItem->tuplePos.offset);
3775
#endif
3776
      code = taosheapadjust((void*)pItems, sizeof(STopBotResItem), 0, pEntryInfo->numOfRes - 1, (const void*)&type,
8,780,119✔
3777
                            topBotResComparFn, NULL, !isTopQuery);
8,780,119✔
3778
      if (code != TSDB_CODE_SUCCESS) {
8,740,507!
3779
        return code;
×
3780
      }
3781
    }
3782
  }
3783

3784
  return TSDB_CODE_SUCCESS;
118,944,210✔
3785
}
3786

3787
/*
3788
 * +------------------------------------+--------------+--------------+
3789
 * |            null bitmap             |              |              |
3790
 * |(n columns, one bit for each column)| src column #1| src column #2|
3791
 * +------------------------------------+--------------+--------------+
3792
 */
3793
int32_t serializeTupleData(const SSDataBlock* pSrcBlock, int32_t rowIndex, SSubsidiaryResInfo* pSubsidiaryies,
185,848,979✔
3794
                           char* buf, char** res) {
3795
  char* nullList = buf;
185,848,979✔
3796
  char* pStart = (char*)(nullList + sizeof(bool) * pSubsidiaryies->num);
185,848,979✔
3797

3798
  int32_t offset = 0;
185,848,979✔
3799
  for (int32_t i = 0; i < pSubsidiaryies->num; ++i) {
371,544,367✔
3800
    SqlFunctionCtx* pc = pSubsidiaryies->pCtx[i];
185,879,982✔
3801

3802
    // group_key function has its own process function
3803
    // do not process there
3804
    if (fmIsGroupKeyFunc(pc->functionId)) {
185,879,982!
3805
      continue;
×
3806
    }
3807

3808
    SFunctParam* pFuncParam = &pc->pExpr->base.pParam[0];
185,858,982✔
3809
    int32_t      srcSlotId = pFuncParam->pCol->slotId;
185,858,982✔
3810

3811
    SColumnInfoData* pCol = taosArrayGet(pSrcBlock->pDataBlock, srcSlotId);
185,858,982✔
3812
    if (NULL == pCol) {
185,695,388!
3813
      return TSDB_CODE_OUT_OF_RANGE;
×
3814
    }
3815
    if ((nullList[i] = colDataIsNull_s(pCol, rowIndex)) == true) {
371,390,776✔
3816
      offset += pCol->info.bytes;
742✔
3817
      continue;
742✔
3818
    }
3819

3820
    char* p = colDataGetData(pCol, rowIndex);
185,694,646!
3821
    if (IS_VAR_DATA_TYPE(pCol->info.type)) {
185,694,646!
3822
      (void)memcpy(pStart + offset, p, (pCol->info.type == TSDB_DATA_TYPE_JSON) ? getJsonValueLen(p) : varDataTLen(p));
56,316!
3823
    } else {
3824
      (void)memcpy(pStart + offset, p, pCol->info.bytes);
185,638,330✔
3825
    }
3826

3827
    offset += pCol->info.bytes;
185,694,646✔
3828
  }
3829

3830
  *res = buf;
185,664,385✔
3831
  return TSDB_CODE_SUCCESS;
185,664,385✔
3832
}
3833

3834
static int32_t doSaveTupleData(SSerializeDataHandle* pHandle, const void* pBuf, size_t length, SWinKey* key,
215,080,770✔
3835
                               STuplePos* pPos, SFunctionStateStore* pStore) {
3836
  STuplePos p = {0};
215,080,770✔
3837
  if (pHandle->pBuf != NULL) {
215,080,770✔
3838
    SFilePage* pPage = NULL;
215,056,132✔
3839

3840
    if (pHandle->currentPage == -1) {
215,056,132✔
3841
      pPage = getNewBufPage(pHandle->pBuf, &pHandle->currentPage);
615,634✔
3842
      if (pPage == NULL) {
615,640!
3843
        return terrno;
×
3844
      }
3845
      pPage->num = sizeof(SFilePage);
615,640✔
3846
    } else {
3847
      pPage = getBufPage(pHandle->pBuf, pHandle->currentPage);
214,440,498✔
3848
      if (pPage == NULL) {
214,414,150!
3849
        return terrno;
×
3850
      }
3851
      if (pPage->num + length > getBufPageSize(pHandle->pBuf)) {
214,414,150✔
3852
        // current page is all used, let's prepare a new buffer page
3853
        releaseBufPage(pHandle->pBuf, pPage);
1,306,568✔
3854
        pPage = getNewBufPage(pHandle->pBuf, &pHandle->currentPage);
1,306,568✔
3855
        if (pPage == NULL) {
1,306,568!
3856
          return terrno;
×
3857
        }
3858
        pPage->num = sizeof(SFilePage);
1,306,568✔
3859
      }
3860
    }
3861

3862
    p = (STuplePos){.pageId = pHandle->currentPage, .offset = pPage->num};
215,022,916✔
3863
    (void)memcpy(pPage->data + pPage->num, pBuf, length);
215,022,916✔
3864

3865
    pPage->num += length;
215,022,916✔
3866
    setBufPageDirty(pPage, true);
215,022,916✔
3867
    releaseBufPage(pHandle->pBuf, pPage);
214,962,924✔
3868
  } else {  // other tuple save policy
3869
    if (pStore->streamStateFuncPut(pHandle->pState, key, pBuf, length) >= 0) {
24,638!
3870
      p.streamTupleKey = *key;
29,967✔
3871
    }
3872
  }
3873

3874
  *pPos = p;
214,921,540✔
3875
  return TSDB_CODE_SUCCESS;
214,921,540✔
3876
}
3877

3878
int32_t saveTupleData(SqlFunctionCtx* pCtx, int32_t rowIndex, const SSDataBlock* pSrcBlock, STuplePos* pPos) {
166,547,505✔
3879
  int32_t code = prepareBuf(pCtx);
166,547,505✔
3880
  if (TSDB_CODE_SUCCESS != code) {
166,528,512!
3881
    return code;
×
3882
  }
3883

3884
  SWinKey key = {0};
166,528,512✔
3885
  if (pCtx->saveHandle.pBuf == NULL) {
166,528,512✔
3886
    SColumnInfoData* pColInfo = taosArrayGet(pSrcBlock->pDataBlock, pCtx->saveHandle.pState->tsIndex);
29,967✔
3887
    if (NULL == pColInfo) {
29,966!
3888
      return TSDB_CODE_OUT_OF_RANGE;
×
3889
    }
3890
    if (pColInfo->info.type != TSDB_DATA_TYPE_TIMESTAMP) {
29,966!
3891
      return TSDB_CODE_FUNC_FUNTION_PARA_TYPE;
×
3892
    }
3893
    key.groupId = pSrcBlock->info.id.groupId;
29,966✔
3894
    key.ts = *(int64_t*)colDataGetData(pColInfo, rowIndex);
29,966!
3895
  }
3896

3897
  char* buf = NULL;
166,528,511✔
3898
  code = serializeTupleData(pSrcBlock, rowIndex, &pCtx->subsidiaries, pCtx->subsidiaries.buf, &buf);
166,528,511✔
3899
  if (TSDB_CODE_SUCCESS != code) {
166,416,825!
3900
    return code;
×
3901
  }
3902
  return doSaveTupleData(&pCtx->saveHandle, buf, pCtx->subsidiaries.rowLen, &key, pPos, pCtx->pStore);
166,416,825✔
3903
}
3904

3905
static int32_t doUpdateTupleData(SSerializeDataHandle* pHandle, const void* pBuf, size_t length, STuplePos* pPos,
19,340,477✔
3906
                                 SFunctionStateStore* pStore) {
3907
  if (pHandle->pBuf != NULL) {
19,340,477✔
3908
    SFilePage* pPage = getBufPage(pHandle->pBuf, pPos->pageId);
19,287,100✔
3909
    if (pPage == NULL) {
19,286,080!
3910
      return terrno;
×
3911
    }
3912
    (void)memcpy(pPage->data + pPos->offset, pBuf, length);
19,286,080✔
3913
    setBufPageDirty(pPage, true);
19,286,080✔
3914
    releaseBufPage(pHandle->pBuf, pPage);
19,283,607✔
3915
  } else {
3916
    int32_t code = pStore->streamStateFuncPut(pHandle->pState, &pPos->streamTupleKey, pBuf, length);
53,377✔
3917
    if (TSDB_CODE_SUCCESS != code) {
53,483!
3918
      return code;
×
3919
    }
3920
  }
3921

3922
  return TSDB_CODE_SUCCESS;
19,333,932✔
3923
}
3924

3925
int32_t updateTupleData(SqlFunctionCtx* pCtx, int32_t rowIndex, const SSDataBlock* pSrcBlock, STuplePos* pPos) {
19,344,776✔
3926
  int32_t code = prepareBuf(pCtx);
19,344,776✔
3927
  if (TSDB_CODE_SUCCESS != code) {
19,344,326!
3928
    return code;
×
3929
  }
3930

3931
  char* buf = NULL;
19,344,326✔
3932
  code = serializeTupleData(pSrcBlock, rowIndex, &pCtx->subsidiaries, pCtx->subsidiaries.buf, &buf);
19,344,326✔
3933
  if (TSDB_CODE_SUCCESS != code) {
19,340,369!
3934
    return code;
×
3935
  }
3936
  return doUpdateTupleData(&pCtx->saveHandle, buf, pCtx->subsidiaries.rowLen, pPos, pCtx->pStore);
19,340,369✔
3937
}
3938

3939
static int32_t doLoadTupleData(SSerializeDataHandle* pHandle, const STuplePos* pPos, SFunctionStateStore* pStore,
138,246,653✔
3940
                               char** value) {
3941
  if (pHandle->pBuf != NULL) {
138,246,653✔
3942
    SFilePage* pPage = getBufPage(pHandle->pBuf, pPos->pageId);
138,219,772✔
3943
    if (pPage == NULL) {
138,267,177!
3944
      *value = NULL;
×
3945
      return terrno;
×
3946
    }
3947
    *value = pPage->data + pPos->offset;
138,267,177✔
3948
    releaseBufPage(pHandle->pBuf, pPage);
138,267,177✔
3949
    return TSDB_CODE_SUCCESS;
138,234,746✔
3950
  } else {
3951
    *value = NULL;
26,881✔
3952
    int32_t vLen;
3953
    int32_t code = pStore->streamStateFuncGet(pHandle->pState, &pPos->streamTupleKey, (void**)(value), &vLen);
26,881✔
3954
    if (TSDB_CODE_SUCCESS != code) {
30,232!
3955
      return code;
×
3956
    }
3957
    return TSDB_CODE_SUCCESS;
30,232✔
3958
  }
3959
}
3960

3961
int32_t loadTupleData(SqlFunctionCtx* pCtx, const STuplePos* pPos, char** value) {
138,158,424✔
3962
  return doLoadTupleData(&pCtx->saveHandle, pPos, pCtx->pStore, value);
138,158,424✔
3963
}
3964

3965
int32_t topBotFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
45,987,860✔
3966
  int32_t code = TSDB_CODE_SUCCESS;
45,987,860✔
3967

3968
  SResultRowEntryInfo* pEntryInfo = GET_RES_INFO(pCtx);
45,987,860✔
3969
  STopBotRes*          pRes = getTopBotOutputInfo(pCtx);
45,987,860✔
3970

3971
  int16_t type = pCtx->pExpr->base.resSchema.type;
45,976,835✔
3972
  int32_t slotId = pCtx->pExpr->base.resSchema.slotId;
45,976,835✔
3973

3974
  SColumnInfoData* pCol = taosArrayGet(pBlock->pDataBlock, slotId);
45,976,835✔
3975
  if (NULL == pCol) {
45,956,736!
3976
    return TSDB_CODE_OUT_OF_RANGE;
×
3977
  }
3978

3979
  // todo assign the tag value and the corresponding row data
3980
  int32_t currentRow = pBlock->info.rows;
45,956,736✔
3981
  if (pEntryInfo->numOfRes <= 0) {
45,956,736✔
3982
    colDataSetNULL(pCol, currentRow);
516!
3983
    code = setSelectivityValue(pCtx, pBlock, &pRes->nullTuplePos, currentRow);
516✔
3984
    return code;
516✔
3985
  }
3986
  for (int32_t i = 0; i < pEntryInfo->numOfRes; ++i) {
120,702,167✔
3987
    STopBotResItem* pItem = &pRes->pItems[i];
74,791,580✔
3988
    code = colDataSetVal(pCol, currentRow, (const char*)&pItem->v.i, false);
74,791,580✔
3989
    if (TSDB_CODE_SUCCESS != code) {
74,792,158!
3990
      return code;
×
3991
    }
3992
#ifdef BUF_PAGE_DEBUG
3993
    qDebug("page_finalize i:%d,item:%p,pageId:%d, offset:%d\n", i, pItem, pItem->tuplePos.pageId,
3994
           pItem->tuplePos.offset);
3995
#endif
3996
    code = setSelectivityValue(pCtx, pBlock, &pRes->pItems[i].tuplePos, currentRow);
74,792,158✔
3997
    if (TSDB_CODE_SUCCESS != code) {
74,745,947!
3998
      return code;
×
3999
    }
4000
    currentRow += 1;
74,745,947✔
4001
  }
4002

4003
  return code;
45,910,587✔
4004
}
4005

4006
int32_t addResult(SqlFunctionCtx* pCtx, STopBotResItem* pSourceItem, int16_t type, bool isTopQuery) {
×
4007
  SResultRowEntryInfo* pEntryInfo = GET_RES_INFO(pCtx);
×
4008
  STopBotRes*          pRes = getTopBotOutputInfo(pCtx);
×
4009
  STopBotResItem*      pItems = pRes->pItems;
×
4010
  int32_t              code = TSDB_CODE_SUCCESS;
×
4011

4012
  // not full yet
4013
  if (pEntryInfo->numOfRes < pRes->maxSize) {
×
4014
    STopBotResItem* pItem = &pItems[pEntryInfo->numOfRes];
×
4015
    pItem->v = pSourceItem->v;
×
4016
    pItem->uid = pSourceItem->uid;
×
4017
    pItem->tuplePos.pageId = -1;
×
4018
    replaceTupleData(&pItem->tuplePos, &pSourceItem->tuplePos);
×
4019
    pEntryInfo->numOfRes++;
×
4020
    code = taosheapsort((void*)pItems, sizeof(STopBotResItem), pEntryInfo->numOfRes, (const void*)&type,
×
4021
                        topBotResComparFn, !isTopQuery);
×
4022
    if (TSDB_CODE_SUCCESS != code) {
×
4023
      return code;
×
4024
    }
4025
  } else {  // replace the minimum value in the result
4026
    if ((isTopQuery && ((IS_SIGNED_NUMERIC_TYPE(type) && pSourceItem->v.i > pItems[0].v.i) ||
×
4027
                        (IS_UNSIGNED_NUMERIC_TYPE(type) && pSourceItem->v.u > pItems[0].v.u) ||
×
4028
                        (TSDB_DATA_TYPE_FLOAT == type && pSourceItem->v.f > pItems[0].v.f) ||
×
4029
                        (TSDB_DATA_TYPE_DOUBLE == type && pSourceItem->v.d > pItems[0].v.d))) ||
×
4030
        (!isTopQuery && ((IS_SIGNED_NUMERIC_TYPE(type) && pSourceItem->v.i < pItems[0].v.i) ||
×
4031
                         (IS_UNSIGNED_NUMERIC_TYPE(type) && pSourceItem->v.u < pItems[0].v.u) ||
×
4032
                         (TSDB_DATA_TYPE_FLOAT == type && pSourceItem->v.f < pItems[0].v.f) ||
×
4033
                         (TSDB_DATA_TYPE_DOUBLE == type && pSourceItem->v.d < pItems[0].v.d)))) {
×
4034
      // replace the old data and the coresponding tuple data
4035
      STopBotResItem* pItem = &pItems[0];
×
4036
      pItem->v = pSourceItem->v;
×
4037
      pItem->uid = pSourceItem->uid;
×
4038

4039
      // save the data of this tuple by over writing the old data
4040
      replaceTupleData(&pItem->tuplePos, &pSourceItem->tuplePos);
×
4041
      code = taosheapadjust((void*)pItems, sizeof(STopBotResItem), 0, pEntryInfo->numOfRes - 1, (const void*)&type,
×
4042
                            topBotResComparFn, NULL, !isTopQuery);
×
4043
      if (TSDB_CODE_SUCCESS != code) {
×
4044
        return code;
×
4045
      }
4046
    }
4047
  }
4048
  return code;
×
4049
}
4050

4051
int32_t topCombine(SqlFunctionCtx* pDestCtx, SqlFunctionCtx* pSourceCtx) {
×
4052
  SResultRowEntryInfo* pSResInfo = GET_RES_INFO(pSourceCtx);
×
4053
  STopBotRes*          pSBuf = getTopBotOutputInfo(pSourceCtx);
×
4054
  int16_t              type = pSBuf->type;
×
4055
  int32_t              code = TSDB_CODE_SUCCESS;
×
4056
  for (int32_t i = 0; i < pSResInfo->numOfRes; i++) {
×
4057
    code = addResult(pDestCtx, pSBuf->pItems + i, type, true);
×
4058
    if (TSDB_CODE_SUCCESS != code) {
×
4059
      return code;
×
4060
    }
4061
  }
4062
  return TSDB_CODE_SUCCESS;
×
4063
}
4064

4065
int32_t bottomCombine(SqlFunctionCtx* pDestCtx, SqlFunctionCtx* pSourceCtx) {
×
4066
  SResultRowEntryInfo* pSResInfo = GET_RES_INFO(pSourceCtx);
×
4067
  STopBotRes*          pSBuf = getTopBotOutputInfo(pSourceCtx);
×
4068
  int16_t              type = pSBuf->type;
×
4069
  int32_t              code = TSDB_CODE_SUCCESS;
×
4070
  for (int32_t i = 0; i < pSResInfo->numOfRes; i++) {
×
4071
    code = addResult(pDestCtx, pSBuf->pItems + i, type, false);
×
4072
    if (TSDB_CODE_SUCCESS != code) {
×
4073
      return code;
×
4074
    }
4075
  }
4076
  return TSDB_CODE_SUCCESS;
×
4077
}
4078

4079
int32_t getSpreadInfoSize() { return (int32_t)sizeof(SSpreadInfo); }
1,047,844✔
4080

4081
bool getSpreadFuncEnv(SFunctionNode* UNUSED_PARAM(pFunc), SFuncExecEnv* pEnv) {
107,910✔
4082
  pEnv->calcMemSize = sizeof(SSpreadInfo);
107,910✔
4083
  return true;
107,910✔
4084
}
4085

4086
int32_t spreadFunctionSetup(SqlFunctionCtx* pCtx, SResultRowEntryInfo* pResultInfo) {
3,564,016✔
4087
  if (pResultInfo->initialized) {
3,564,016!
4088
    return TSDB_CODE_SUCCESS;
×
4089
  }
4090
  if (TSDB_CODE_SUCCESS != functionSetup(pCtx, pResultInfo)) {
3,564,016!
4091
    return TSDB_CODE_FUNC_SETUP_ERROR;
×
4092
  }
4093

4094
  SSpreadInfo* pInfo = GET_ROWCELL_INTERBUF(pResultInfo);
3,564,042✔
4095
  SET_DOUBLE_VAL(&pInfo->min, DBL_MAX);
3,564,042✔
4096
  SET_DOUBLE_VAL(&pInfo->max, -DBL_MAX);
3,564,042✔
4097
  pInfo->hasResult = false;
3,564,042✔
4098
  return TSDB_CODE_SUCCESS;
3,564,042✔
4099
}
4100

4101
int32_t spreadFunction(SqlFunctionCtx* pCtx) {
2,570,448✔
4102
  int32_t numOfElems = 0;
2,570,448✔
4103

4104
  // Only the pre-computing information loaded and actual data does not loaded
4105
  SInputColumnInfoData* pInput = &pCtx->input;
2,570,448✔
4106
  SColumnDataAgg*       pAgg = pInput->pColumnDataAgg[0];
2,570,448✔
4107
  int32_t               type = pInput->pData[0]->info.type;
2,570,448✔
4108

4109
  SSpreadInfo* pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
2,570,448✔
4110

4111
  if (pInput->colDataSMAIsSet) {
2,570,448!
4112
    numOfElems = pInput->numOfRows - pAgg->numOfNull;
×
4113
    if (numOfElems == 0) {
×
4114
      goto _spread_over;
×
4115
    }
4116
    double tmin = 0.0, tmax = 0.0;
×
4117
    if (IS_SIGNED_NUMERIC_TYPE(type) || IS_TIMESTAMP_TYPE(type)) {
×
4118
      tmin = (double)GET_INT64_VAL(&pAgg->min);
×
4119
      tmax = (double)GET_INT64_VAL(&pAgg->max);
×
4120
    } else if (IS_FLOAT_TYPE(type)) {
×
4121
      tmin = GET_DOUBLE_VAL(&pAgg->min);
×
4122
      tmax = GET_DOUBLE_VAL(&pAgg->max);
×
4123
    } else if (IS_UNSIGNED_NUMERIC_TYPE(type)) {
×
4124
      tmin = (double)GET_UINT64_VAL(&pAgg->min);
×
4125
      tmax = (double)GET_UINT64_VAL(&pAgg->max);
×
4126
    }
4127

4128
    if (GET_DOUBLE_VAL(&pInfo->min) > tmin) {
×
4129
      SET_DOUBLE_VAL(&pInfo->min, tmin);
×
4130
    }
4131

4132
    if (GET_DOUBLE_VAL(&pInfo->max) < tmax) {
×
4133
      SET_DOUBLE_VAL(&pInfo->max, tmax);
×
4134
    }
4135

4136
  } else {  // computing based on the true data block
4137
    SColumnInfoData* pCol = pInput->pData[0];
2,570,448✔
4138

4139
    int32_t start = pInput->startRowIndex;
2,570,448✔
4140
    // check the valid data one by one
4141
    for (int32_t i = start; i < pInput->numOfRows + start; ++i) {
13,252,179✔
4142
      if (colDataIsNull_f(pCol->nullbitmap, i)) {
10,681,731✔
4143
        continue;
1,387,085✔
4144
      }
4145

4146
      char* data = colDataGetData(pCol, i);
9,294,646!
4147

4148
      double v = 0;
9,294,646✔
4149
      GET_TYPED_DATA(v, double, type, data);
9,294,646!
4150
      if (v < GET_DOUBLE_VAL(&pInfo->min)) {
9,294,646✔
4151
        SET_DOUBLE_VAL(&pInfo->min, v);
2,757,522✔
4152
      }
4153

4154
      if (v > GET_DOUBLE_VAL(&pInfo->max)) {
9,294,646✔
4155
        SET_DOUBLE_VAL(&pInfo->max, v);
3,538,260✔
4156
      }
4157

4158
      numOfElems += 1;
9,294,646✔
4159
    }
4160
  }
4161

4162
_spread_over:
2,570,448✔
4163
  // data in the check operation are all null, not output
4164
  SET_VAL(GET_RES_INFO(pCtx), numOfElems, 1);
2,570,448✔
4165
  if (numOfElems > 0) {
2,570,448✔
4166
    pInfo->hasResult = true;
2,546,080✔
4167
  }
4168

4169
  return TSDB_CODE_SUCCESS;
2,570,448✔
4170
}
4171

4172
static void spreadTransferInfo(SSpreadInfo* pInput, SSpreadInfo* pOutput) {
1,043,004✔
4173
  pOutput->hasResult = pInput->hasResult;
1,043,004✔
4174
  if (pInput->max > pOutput->max) {
1,043,004✔
4175
    pOutput->max = pInput->max;
1,038,575✔
4176
  }
4177

4178
  if (pInput->min < pOutput->min) {
1,043,004✔
4179
    pOutput->min = pInput->min;
1,038,559✔
4180
  }
4181
}
1,043,004✔
4182

4183
int32_t spreadFunctionMerge(SqlFunctionCtx* pCtx) {
1,039,049✔
4184
  SInputColumnInfoData* pInput = &pCtx->input;
1,039,049✔
4185
  SColumnInfoData*      pCol = pInput->pData[0];
1,039,049✔
4186

4187
  if (IS_NULL_TYPE(pCol->info.type)) {
1,039,049!
4188
    SET_VAL(GET_RES_INFO(pCtx), 0, 1);
×
4189
    return TSDB_CODE_SUCCESS;
×
4190
  }
4191

4192
  if (pCol->info.type != TSDB_DATA_TYPE_BINARY) {
1,039,049!
4193
    return TSDB_CODE_FUNC_FUNTION_PARA_TYPE;
×
4194
  }
4195

4196
  SSpreadInfo* pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
1,039,049✔
4197

4198
  int32_t start = pInput->startRowIndex;
1,039,049✔
4199
  for (int32_t i = start; i < start + pInput->numOfRows; ++i) {
2,082,290✔
4200
    if (colDataIsNull_s(pCol, i)) continue;
2,086,482!
4201
    char*        data = colDataGetData(pCol, i);
1,043,241!
4202
    SSpreadInfo* pInputInfo = (SSpreadInfo*)varDataVal(data);
1,043,241✔
4203
    if (pInputInfo->hasResult) {
1,043,241✔
4204
      spreadTransferInfo(pInputInfo, pInfo);
1,043,003✔
4205
    }
4206
  }
4207

4208
  if (pInfo->hasResult) {
1,039,049✔
4209
    GET_RES_INFO(pCtx)->numOfRes = 1;
1,038,877✔
4210
  }
4211

4212
  return TSDB_CODE_SUCCESS;
1,039,049✔
4213
}
4214

4215
int32_t spreadFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
2,500,461✔
4216
  SSpreadInfo* pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
2,500,461✔
4217
  if (pInfo->hasResult == true) {
2,500,461✔
4218
    SET_DOUBLE_VAL(&pInfo->result, pInfo->max - pInfo->min);
2,476,692✔
4219
  } else {
4220
    GET_RES_INFO(pCtx)->isNullRes = 1;
23,769✔
4221
  }
4222
  return functionFinalize(pCtx, pBlock);
2,500,461✔
4223
}
4224

4225
int32_t spreadPartialFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
1,046,296✔
4226
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
1,046,296✔
4227
  SSpreadInfo*         pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
1,046,296✔
4228
  int32_t              resultBytes = getSpreadInfoSize();
1,046,296✔
4229
  char*                res = taosMemoryCalloc(resultBytes + VARSTR_HEADER_SIZE, sizeof(char));
1,046,296!
4230

4231
  if (NULL == res) {
1,046,297!
4232
    return terrno;
×
4233
  }
4234
  (void)memcpy(varDataVal(res), pInfo, resultBytes);
1,046,297✔
4235
  varDataSetLen(res, resultBytes);
1,046,297✔
4236

4237
  int32_t          slotId = pCtx->pExpr->base.resSchema.slotId;
1,046,297✔
4238
  int32_t          code = TSDB_CODE_SUCCESS;
1,046,297✔
4239
  SColumnInfoData* pCol = taosArrayGet(pBlock->pDataBlock, slotId);
1,046,297✔
4240
  if (NULL == pCol) {
1,046,297!
4241
    code = terrno;
×
4242
    goto _exit;
×
4243
  }
4244

4245
  code = colDataSetVal(pCol, pBlock->info.rows, res, false);
1,046,297✔
4246
  if (TSDB_CODE_SUCCESS != code) {
1,046,297!
4247
    goto _exit;
×
4248
  }
4249

4250
_exit:
1,046,297✔
4251
  taosMemoryFree(res);
1,046,297!
4252
  return code;
1,046,297✔
4253
}
4254

4255
int32_t spreadCombine(SqlFunctionCtx* pDestCtx, SqlFunctionCtx* pSourceCtx) {
1✔
4256
  SResultRowEntryInfo* pDResInfo = GET_RES_INFO(pDestCtx);
1✔
4257
  SSpreadInfo*         pDBuf = GET_ROWCELL_INTERBUF(pDResInfo);
1✔
4258

4259
  SResultRowEntryInfo* pSResInfo = GET_RES_INFO(pSourceCtx);
1✔
4260
  SSpreadInfo*         pSBuf = GET_ROWCELL_INTERBUF(pSResInfo);
1✔
4261
  spreadTransferInfo(pSBuf, pDBuf);
1✔
4262
  pDResInfo->numOfRes = TMAX(pDResInfo->numOfRes, pSResInfo->numOfRes);
1✔
4263
  pDResInfo->isNullRes &= pSResInfo->isNullRes;
1✔
4264
  return TSDB_CODE_SUCCESS;
1✔
4265
}
4266

4267
int32_t getElapsedInfoSize() { return (int32_t)sizeof(SElapsedInfo); }
×
4268

4269
bool getElapsedFuncEnv(SFunctionNode* UNUSED_PARAM(pFunc), SFuncExecEnv* pEnv) {
23,701✔
4270
  pEnv->calcMemSize = sizeof(SElapsedInfo);
23,701✔
4271
  return true;
23,701✔
4272
}
4273

4274
int32_t elapsedFunctionSetup(SqlFunctionCtx* pCtx, SResultRowEntryInfo* pResultInfo) {
42,269✔
4275
  if (pResultInfo->initialized) {
42,269!
4276
    return TSDB_CODE_SUCCESS;
×
4277
  }
4278
  if (TSDB_CODE_SUCCESS != functionSetup(pCtx, pResultInfo)) {
42,269!
4279
    return TSDB_CODE_FUNC_SETUP_ERROR;
×
4280
  }
4281

4282
  SElapsedInfo* pInfo = GET_ROWCELL_INTERBUF(pResultInfo);
42,292✔
4283
  pInfo->result = 0;
42,292✔
4284
  pInfo->min = TSKEY_MAX;
42,292✔
4285
  pInfo->max = 0;
42,292✔
4286

4287
  if (pCtx->numOfParams > 1) {
42,292✔
4288
    pInfo->timeUnit = pCtx->param[1].param.i;
24,956✔
4289
  } else {
4290
    pInfo->timeUnit = 1;
17,336✔
4291
  }
4292

4293
  return TSDB_CODE_SUCCESS;
42,292✔
4294
}
4295

4296
int32_t elapsedFunction(SqlFunctionCtx* pCtx) {
46,134✔
4297
  int32_t numOfElems = 0;
46,134✔
4298

4299
  // Only the pre-computing information loaded and actual data does not loaded
4300
  SInputColumnInfoData* pInput = &pCtx->input;
46,134✔
4301
  SColumnDataAgg*       pAgg = pInput->pColumnDataAgg[0];
46,134✔
4302

4303
  SElapsedInfo* pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
46,134✔
4304

4305
  numOfElems = pInput->numOfRows;  // since this is the primary timestamp, no need to exclude NULL values
46,134✔
4306
  if (numOfElems == 0) {
46,134✔
4307
    // for stream
4308
    if (pCtx->end.key != INT64_MIN) {
56!
4309
      pInfo->max = pCtx->end.key + 1;
56✔
4310
    }
4311
    goto _elapsed_over;
56✔
4312
  }
4313

4314
  if (pInput->colDataSMAIsSet) {
46,078!
4315
    if (pInfo->min == TSKEY_MAX) {
×
4316
      pInfo->min = GET_INT64_VAL(&pAgg->min);
×
4317
      pInfo->max = GET_INT64_VAL(&pAgg->max);
×
4318
    } else {
4319
      if (pCtx->order == TSDB_ORDER_ASC) {
×
4320
        pInfo->max = GET_INT64_VAL(&pAgg->max);
×
4321
      } else {
4322
        pInfo->min = GET_INT64_VAL(&pAgg->min);
×
4323
      }
4324
    }
4325
  } else {  // computing based on the true data block
4326
    if (0 == pInput->numOfRows) {
46,078!
4327
      if (pCtx->order == TSDB_ORDER_DESC) {
×
4328
        if (pCtx->end.key != INT64_MIN) {
×
4329
          pInfo->min = pCtx->end.key;
×
4330
        }
4331
      } else {
4332
        if (pCtx->end.key != INT64_MIN) {
×
4333
          pInfo->max = pCtx->end.key + 1;
×
4334
        }
4335
      }
4336
      goto _elapsed_over;
×
4337
    }
4338

4339
    SColumnInfoData* pCol = pInput->pData[0];
46,078✔
4340

4341
    int32_t start = pInput->startRowIndex;
46,078✔
4342
    TSKEY*  ptsList = (int64_t*)colDataGetData(pCol, 0);
46,078!
4343
    if (pCtx->order == TSDB_ORDER_DESC) {
46,078✔
4344
      if (pCtx->start.key == INT64_MIN) {
676!
4345
        pInfo->max = (pInfo->max < ptsList[start]) ? ptsList[start] : pInfo->max;
676✔
4346
      } else {
4347
        pInfo->max = pCtx->start.key + 1;
×
4348
      }
4349

4350
      if (pCtx->end.key == INT64_MIN) {
676!
4351
        pInfo->min =
676✔
4352
            (pInfo->min > ptsList[start + pInput->numOfRows - 1]) ? ptsList[start + pInput->numOfRows - 1] : pInfo->min;
676✔
4353
      } else {
4354
        pInfo->min = pCtx->end.key;
×
4355
      }
4356
    } else {
4357
      if (pCtx->start.key == INT64_MIN) {
45,402✔
4358
        pInfo->min = (pInfo->min > ptsList[start]) ? ptsList[start] : pInfo->min;
42,960✔
4359
      } else {
4360
        pInfo->min = pCtx->start.key;
2,442✔
4361
      }
4362

4363
      if (pCtx->end.key == INT64_MIN) {
45,402✔
4364
        pInfo->max =
42,631✔
4365
            (pInfo->max < ptsList[start + pInput->numOfRows - 1]) ? ptsList[start + pInput->numOfRows - 1] : pInfo->max;
42,631✔
4366
      } else {
4367
        pInfo->max = pCtx->end.key + 1;
2,771✔
4368
      }
4369
    }
4370
  }
4371

4372
_elapsed_over:
46,134✔
4373
  // data in the check operation are all null, not output
4374
  SET_VAL(GET_RES_INFO(pCtx), numOfElems, 1);
46,134✔
4375

4376
  return TSDB_CODE_SUCCESS;
46,134✔
4377
}
4378

4379
static void elapsedTransferInfo(SElapsedInfo* pInput, SElapsedInfo* pOutput) {
×
4380
  pOutput->timeUnit = pInput->timeUnit;
×
4381
  if (pOutput->min > pInput->min) {
×
4382
    pOutput->min = pInput->min;
×
4383
  }
4384

4385
  if (pOutput->max < pInput->max) {
×
4386
    pOutput->max = pInput->max;
×
4387
  }
4388
}
×
4389

4390
int32_t elapsedFunctionMerge(SqlFunctionCtx* pCtx) {
×
4391
  SInputColumnInfoData* pInput = &pCtx->input;
×
4392
  SColumnInfoData*      pCol = pInput->pData[0];
×
4393
  if (pCol->info.type != TSDB_DATA_TYPE_BINARY) {
×
4394
    return TSDB_CODE_FUNC_FUNTION_PARA_TYPE;
×
4395
  }
4396

4397
  SElapsedInfo* pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
×
4398

4399
  int32_t start = pInput->startRowIndex;
×
4400

4401
  for (int32_t i = start; i < start + pInput->numOfRows; ++i) {
×
4402
    char*         data = colDataGetData(pCol, i);
×
4403
    SElapsedInfo* pInputInfo = (SElapsedInfo*)varDataVal(data);
×
4404
    elapsedTransferInfo(pInputInfo, pInfo);
×
4405
  }
4406

4407
  SET_VAL(GET_RES_INFO(pCtx), 1, 1);
×
4408
  return TSDB_CODE_SUCCESS;
×
4409
}
4410

4411
int32_t elapsedFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
42,357✔
4412
  SElapsedInfo* pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
42,357✔
4413
  double        result = (double)pInfo->max - (double)pInfo->min;
42,357✔
4414
  result = (result >= 0) ? result : -result;
42,357✔
4415
  pInfo->result = result / pInfo->timeUnit;
42,357✔
4416
  return functionFinalize(pCtx, pBlock);
42,357✔
4417
}
4418

4419
int32_t elapsedPartialFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
×
4420
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
×
4421
  SElapsedInfo*        pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
×
4422
  int32_t              resultBytes = getElapsedInfoSize();
×
4423
  char*                res = taosMemoryCalloc(resultBytes + VARSTR_HEADER_SIZE, sizeof(char));
×
4424

4425
  if (NULL == res) {
×
4426
    return terrno;
×
4427
  }
4428
  (void)memcpy(varDataVal(res), pInfo, resultBytes);
×
4429
  varDataSetLen(res, resultBytes);
×
4430

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

4439
  code = colDataSetVal(pCol, pBlock->info.rows, res, false);
×
4440
  if (TSDB_CODE_SUCCESS != code) {
×
4441
    goto _exit;
×
4442
  }
4443
_exit:
×
4444
  taosMemoryFree(res);
×
4445
  return code;
×
4446
}
4447

4448
int32_t elapsedCombine(SqlFunctionCtx* pDestCtx, SqlFunctionCtx* pSourceCtx) {
×
4449
  SResultRowEntryInfo* pDResInfo = GET_RES_INFO(pDestCtx);
×
4450
  SElapsedInfo*        pDBuf = GET_ROWCELL_INTERBUF(pDResInfo);
×
4451

4452
  SResultRowEntryInfo* pSResInfo = GET_RES_INFO(pSourceCtx);
×
4453
  SElapsedInfo*        pSBuf = GET_ROWCELL_INTERBUF(pSResInfo);
×
4454

4455
  elapsedTransferInfo(pSBuf, pDBuf);
×
4456
  pDResInfo->numOfRes = TMAX(pDResInfo->numOfRes, pSResInfo->numOfRes);
×
4457
  pDResInfo->isNullRes &= pSResInfo->isNullRes;
×
4458
  return TSDB_CODE_SUCCESS;
×
4459
}
4460

4461
int32_t getHistogramInfoSize() {
2,215,245✔
4462
  return (int32_t)sizeof(SHistoFuncInfo) + HISTOGRAM_MAX_BINS_NUM * sizeof(SHistoFuncBin);
2,215,245✔
4463
}
4464

4465
bool getHistogramFuncEnv(SFunctionNode* UNUSED_PARAM(pFunc), SFuncExecEnv* pEnv) {
109,785✔
4466
  pEnv->calcMemSize = sizeof(SHistoFuncInfo) + HISTOGRAM_MAX_BINS_NUM * sizeof(SHistoFuncBin);
109,785✔
4467
  return true;
109,785✔
4468
}
4469

4470
static int8_t getHistogramBinType(char* binTypeStr) {
13,828,554✔
4471
  int8_t binType;
4472
  if (strcasecmp(binTypeStr, "user_input") == 0) {
13,828,554✔
4473
    binType = USER_INPUT_BIN;
2,997✔
4474
  } else if (strcasecmp(binTypeStr, "linear_bin") == 0) {
13,825,557✔
4475
    binType = LINEAR_BIN;
1,756✔
4476
  } else if (strcasecmp(binTypeStr, "log_bin") == 0) {
13,823,801!
4477
    binType = LOG_BIN;
13,824,265✔
4478
  } else {
4479
    binType = UNKNOWN_BIN;
×
4480
  }
4481

4482
  return binType;
13,828,554✔
4483
}
4484

4485
static int32_t getHistogramBinDesc(SHistoFuncInfo* pInfo, char* binDescStr, int8_t binType, bool normalized) {
13,828,643✔
4486
  cJSON*  binDesc = cJSON_Parse(binDescStr);
13,828,643✔
4487
  int32_t numOfBins;
4488
  double* intervals;
4489
  if (cJSON_IsObject(binDesc)) { /* linaer/log bins */
13,828,666✔
4490
    int32_t numOfParams = cJSON_GetArraySize(binDesc);
13,825,637✔
4491
    int32_t startIndex;
4492
    if (numOfParams != 4) {
13,825,596!
4493
      cJSON_Delete(binDesc);
×
4494
      return TSDB_CODE_FAILED;
×
4495
    }
4496

4497
    cJSON* start = cJSON_GetObjectItem(binDesc, "start");
13,825,596✔
4498
    cJSON* factor = cJSON_GetObjectItem(binDesc, "factor");
13,825,930✔
4499
    cJSON* width = cJSON_GetObjectItem(binDesc, "width");
13,825,935✔
4500
    cJSON* count = cJSON_GetObjectItem(binDesc, "count");
13,824,174✔
4501
    cJSON* infinity = cJSON_GetObjectItem(binDesc, "infinity");
13,825,705✔
4502

4503
    if (!cJSON_IsNumber(start) || !cJSON_IsNumber(count) || !cJSON_IsBool(infinity)) {
13,826,057!
4504
      cJSON_Delete(binDesc);
×
4505
      return TSDB_CODE_FAILED;
×
4506
    }
4507

4508
    if (count->valueint <= 0 || count->valueint > 1000) {  // limit count to 1000
13,826,012!
4509
      cJSON_Delete(binDesc);
×
4510
      return TSDB_CODE_FAILED;
×
4511
    }
4512

4513
    if (isinf(start->valuedouble) || (width != NULL && isinf(width->valuedouble)) ||
13,826,017!
4514
        (factor != NULL && isinf(factor->valuedouble)) || (count != NULL && isinf(count->valuedouble))) {
13,826,017!
4515
      cJSON_Delete(binDesc);
×
4516
      return TSDB_CODE_FAILED;
×
4517
    }
4518

4519
    int32_t counter = (int32_t)count->valueint;
13,826,017✔
4520
    if (infinity->valueint == false) {
13,826,017✔
4521
      startIndex = 0;
13,816,755✔
4522
      numOfBins = counter + 1;
13,816,755✔
4523
    } else {
4524
      startIndex = 1;
9,262✔
4525
      numOfBins = counter + 3;
9,262✔
4526
    }
4527

4528
    intervals = taosMemoryCalloc(numOfBins, sizeof(double));
13,826,017!
4529
    if (NULL == intervals) {
13,826,137!
4530
      cJSON_Delete(binDesc);
×
4531
      qError("histogram function out of memory");
×
4532
      return terrno;
×
4533
    }
4534
    if (cJSON_IsNumber(width) && factor == NULL && binType == LINEAR_BIN) {
13,826,137!
4535
      // linear bin process
4536
      if (width->valuedouble == 0) {
1,756!
4537
        taosMemoryFree(intervals);
×
4538
        cJSON_Delete(binDesc);
×
4539
        return TSDB_CODE_FAILED;
×
4540
      }
4541
      for (int i = 0; i < counter + 1; ++i) {
9,992✔
4542
        intervals[startIndex] = start->valuedouble + i * width->valuedouble;
8,236✔
4543
        if (isinf(intervals[startIndex])) {
8,236!
4544
          taosMemoryFree(intervals);
×
4545
          cJSON_Delete(binDesc);
×
4546
          return TSDB_CODE_FAILED;
×
4547
        }
4548
        startIndex++;
8,236✔
4549
      }
4550
    } else if (cJSON_IsNumber(factor) && width == NULL && binType == LOG_BIN) {
13,824,362!
4551
      // log bin process
4552
      if (start->valuedouble == 0) {
13,824,331!
4553
        taosMemoryFree(intervals);
×
4554
        cJSON_Delete(binDesc);
×
4555
        return TSDB_CODE_FAILED;
×
4556
      }
4557
      if (factor->valuedouble < 0 || factor->valuedouble == 0 || factor->valuedouble == 1) {
13,824,331!
4558
        taosMemoryFree(intervals);
×
4559
        cJSON_Delete(binDesc);
×
4560
        return TSDB_CODE_FAILED;
×
4561
      }
4562
      for (int i = 0; i < counter + 1; ++i) {
96,761,501✔
4563
        intervals[startIndex] = start->valuedouble * pow(factor->valuedouble, i * 1.0);
82,937,169✔
4564
        if (isinf(intervals[startIndex])) {
82,937,169!
4565
          taosMemoryFree(intervals);
×
4566
          cJSON_Delete(binDesc);
×
4567
          return TSDB_CODE_FAILED;
×
4568
        }
4569
        startIndex++;
82,937,169✔
4570
      }
4571
    } else {
4572
      taosMemoryFree(intervals);
×
4573
      cJSON_Delete(binDesc);
×
4574
      return TSDB_CODE_FAILED;
×
4575
    }
4576

4577
    if (infinity->valueint == true) {
13,826,088✔
4578
      intervals[0] = -INFINITY;
9,328✔
4579
      intervals[numOfBins - 1] = INFINITY;
9,328✔
4580
      // in case of desc bin orders, -inf/inf should be swapped
4581
      if (numOfBins < 4) {
9,328!
4582
        return TSDB_CODE_FAILED;
×
4583
      }
4584
      if (intervals[1] > intervals[numOfBins - 2]) {
9,328✔
4585
        TSWAP(intervals[0], intervals[numOfBins - 1]);
8,364✔
4586
      }
4587
    }
4588
  } else if (cJSON_IsArray(binDesc)) { /* user input bins */
2,997!
4589
    if (binType != USER_INPUT_BIN) {
2,997!
4590
      cJSON_Delete(binDesc);
×
4591
      return TSDB_CODE_FAILED;
×
4592
    }
4593
    numOfBins = cJSON_GetArraySize(binDesc);
2,997✔
4594
    intervals = taosMemoryCalloc(numOfBins, sizeof(double));
2,997!
4595
    if (NULL == intervals) {
2,997!
4596
      cJSON_Delete(binDesc);
×
4597
      qError("histogram function out of memory");
×
4598
      return terrno;
×
4599
    }
4600
    cJSON* bin = binDesc->child;
2,997✔
4601
    if (bin == NULL) {
2,997!
4602
      taosMemoryFree(intervals);
×
4603
      cJSON_Delete(binDesc);
×
4604
      return TSDB_CODE_FAILED;
×
4605
    }
4606
    int i = 0;
2,997✔
4607
    while (bin) {
12,680✔
4608
      intervals[i] = bin->valuedouble;
9,683✔
4609
      if (!cJSON_IsNumber(bin)) {
9,683!
4610
        taosMemoryFree(intervals);
×
4611
        cJSON_Delete(binDesc);
×
4612
        return TSDB_CODE_FAILED;
×
4613
      }
4614
      if (i != 0 && intervals[i] <= intervals[i - 1]) {
9,683!
4615
        taosMemoryFree(intervals);
×
4616
        cJSON_Delete(binDesc);
×
4617
        return TSDB_CODE_FAILED;
×
4618
      }
4619
      bin = bin->next;
9,683✔
4620
      i++;
9,683✔
4621
    }
4622
  } else {
4623
    cJSON_Delete(binDesc);
×
4624
    return TSDB_CODE_FAILED;
×
4625
  }
4626

4627
  pInfo->numOfBins = numOfBins - 1;
13,829,085✔
4628
  pInfo->normalized = normalized;
13,829,085✔
4629
  for (int32_t i = 0; i < pInfo->numOfBins; ++i) {
82,979,120✔
4630
    pInfo->bins[i].lower = intervals[i] < intervals[i + 1] ? intervals[i] : intervals[i + 1];
69,150,035✔
4631
    pInfo->bins[i].upper = intervals[i + 1] > intervals[i] ? intervals[i + 1] : intervals[i];
69,150,035✔
4632
    pInfo->bins[i].count = 0;
69,150,035✔
4633
  }
4634

4635
  taosMemoryFree(intervals);
13,829,085✔
4636
  cJSON_Delete(binDesc);
13,829,201✔
4637

4638
  return TSDB_CODE_SUCCESS;
13,829,091✔
4639
}
4640

4641
int32_t histogramFunctionSetup(SqlFunctionCtx* pCtx, SResultRowEntryInfo* pResultInfo) {
13,828,780✔
4642
  if (pResultInfo->initialized) {
13,828,780!
4643
    return TSDB_CODE_SUCCESS;
×
4644
  }
4645
  if (TSDB_CODE_SUCCESS != functionSetup(pCtx, pResultInfo)) {
13,828,780!
4646
    return TSDB_CODE_FUNC_SETUP_ERROR;
×
4647
  }
4648

4649
  SHistoFuncInfo* pInfo = GET_ROWCELL_INTERBUF(pResultInfo);
13,828,848✔
4650
  pInfo->numOfBins = 0;
13,828,848✔
4651
  pInfo->totalCount = 0;
13,828,848✔
4652
  pInfo->normalized = 0;
13,828,848✔
4653

4654
  char* binTypeStr = taosStrndup(varDataVal(pCtx->param[1].param.pz), varDataLen(pCtx->param[1].param.pz));
13,828,848✔
4655
  if (binTypeStr == NULL) {
13,828,579!
4656
    return terrno;
×
4657
  }
4658
  int8_t binType = getHistogramBinType(binTypeStr);
13,828,579✔
4659
  taosMemoryFree(binTypeStr);
13,828,804!
4660

4661
  if (binType == UNKNOWN_BIN) {
13,828,595!
4662
    return TSDB_CODE_FUNC_FUNTION_PARA_VALUE;
×
4663
  }
4664
  char* binDesc = taosStrndup(varDataVal(pCtx->param[2].param.pz), varDataLen(pCtx->param[2].param.pz));
13,828,595✔
4665
  if (binDesc == NULL) {
13,828,660!
4666
    return terrno;
×
4667
  }
4668
  int64_t normalized = pCtx->param[3].param.i;
13,828,660✔
4669
  if (normalized != 0 && normalized != 1) {
13,828,660!
4670
    taosMemoryFree(binDesc);
×
4671
    return TSDB_CODE_FUNC_FUNTION_PARA_VALUE;
×
4672
  }
4673
  int32_t code = getHistogramBinDesc(pInfo, binDesc, binType, (bool)normalized);
13,828,660✔
4674
  if (TSDB_CODE_SUCCESS != code) {
13,829,088!
4675
    taosMemoryFree(binDesc);
×
4676
    return code;
×
4677
  }
4678
  taosMemoryFree(binDesc);
13,829,088!
4679

4680
  return TSDB_CODE_SUCCESS;
13,828,995✔
4681
}
4682

4683
static int32_t histogramFunctionImpl(SqlFunctionCtx* pCtx, bool isPartial) {
15,950,471✔
4684
  SHistoFuncInfo* pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
15,950,471✔
4685

4686
  SInputColumnInfoData* pInput = &pCtx->input;
15,950,471✔
4687
  SColumnInfoData*      pCol = pInput->pData[0];
15,950,471✔
4688

4689
  int32_t type = pInput->pData[0]->info.type;
15,950,471✔
4690

4691
  int32_t start = pInput->startRowIndex;
15,950,471✔
4692
  int32_t numOfRows = pInput->numOfRows;
15,950,471✔
4693

4694
  int32_t numOfElems = 0;
15,950,471✔
4695
  for (int32_t i = start; i < numOfRows + start; ++i) {
59,506,216✔
4696
    if (pCol->hasNull && colDataIsNull_f(pCol->nullbitmap, i)) {
43,555,745✔
4697
      continue;
534,866✔
4698
    }
4699

4700
    numOfElems++;
43,020,879✔
4701

4702
    char*  data = colDataGetData(pCol, i);
43,020,879!
4703
    double v;
4704
    GET_TYPED_DATA(v, double, type, data);
43,020,879!
4705

4706
    for (int32_t k = 0; k < pInfo->numOfBins; ++k) {
237,163,149✔
4707
      if (v > pInfo->bins[k].lower && v <= pInfo->bins[k].upper) {
201,381,877✔
4708
        pInfo->bins[k].count++;
7,239,607✔
4709
        pInfo->totalCount++;
7,239,607✔
4710
        break;
7,239,607✔
4711
      }
4712
    }
4713
  }
4714

4715
  if (!isPartial) {
15,950,471✔
4716
    GET_RES_INFO(pCtx)->numOfRes = pInfo->numOfBins;
11,645,503✔
4717
  } else {
4718
    GET_RES_INFO(pCtx)->numOfRes = 1;
4,304,968✔
4719
  }
4720
  return TSDB_CODE_SUCCESS;
15,950,471✔
4721
}
4722

4723
int32_t histogramFunction(SqlFunctionCtx* pCtx) { return histogramFunctionImpl(pCtx, false); }
11,645,532✔
4724

4725
int32_t histogramFunctionPartial(SqlFunctionCtx* pCtx) { return histogramFunctionImpl(pCtx, true); }
4,305,342✔
4726

4727
static void histogramTransferInfo(SHistoFuncInfo* pInput, SHistoFuncInfo* pOutput) {
2,198,720✔
4728
  pOutput->normalized = pInput->normalized;
2,198,720✔
4729
  pOutput->numOfBins = pInput->numOfBins;
2,198,720✔
4730
  pOutput->totalCount += pInput->totalCount;
2,198,720✔
4731
  for (int32_t k = 0; k < pOutput->numOfBins; ++k) {
13,194,915✔
4732
    pOutput->bins[k].lower = pInput->bins[k].lower;
10,996,195✔
4733
    pOutput->bins[k].upper = pInput->bins[k].upper;
10,996,195✔
4734
    pOutput->bins[k].count += pInput->bins[k].count;
10,996,195✔
4735
  }
4736
}
2,198,720✔
4737

4738
int32_t histogramFunctionMerge(SqlFunctionCtx* pCtx) {
2,198,720✔
4739
  SInputColumnInfoData* pInput = &pCtx->input;
2,198,720✔
4740
  SColumnInfoData*      pCol = pInput->pData[0];
2,198,720✔
4741
  if (pCol->info.type != TSDB_DATA_TYPE_BINARY) {
2,198,720!
4742
    return TSDB_CODE_FUNC_FUNTION_PARA_TYPE;
×
4743
  }
4744

4745
  SHistoFuncInfo* pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
2,198,720✔
4746

4747
  int32_t start = pInput->startRowIndex;
2,198,720✔
4748

4749
  for (int32_t i = start; i < start + pInput->numOfRows; ++i) {
4,397,440✔
4750
    char*           data = colDataGetData(pCol, i);
2,198,720!
4751
    SHistoFuncInfo* pInputInfo = (SHistoFuncInfo*)varDataVal(data);
2,198,720✔
4752
    histogramTransferInfo(pInputInfo, pInfo);
2,198,720✔
4753
  }
4754

4755
  SET_VAL(GET_RES_INFO(pCtx), pInfo->numOfBins, pInfo->numOfBins);
2,198,720!
4756
  return TSDB_CODE_SUCCESS;
2,198,720✔
4757
}
4758

4759
int32_t histogramFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
13,761,486✔
4760
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
13,761,486✔
4761
  SHistoFuncInfo*      pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
13,761,486✔
4762
  int32_t              slotId = pCtx->pExpr->base.resSchema.slotId;
13,761,486✔
4763
  SColumnInfoData*     pCol = taosArrayGet(pBlock->pDataBlock, slotId);
13,761,486✔
4764
  int32_t              code = TSDB_CODE_SUCCESS;
13,761,300✔
4765

4766
  int32_t currentRow = pBlock->info.rows;
13,761,300✔
4767
  if (NULL == pCol) {
13,761,300!
4768
    return TSDB_CODE_OUT_OF_RANGE;
×
4769
  }
4770

4771
  if (pInfo->normalized) {
13,761,300✔
4772
    for (int32_t k = 0; k < pResInfo->numOfRes; ++k) {
82,531,895✔
4773
      if (pInfo->totalCount != 0) {
68,777,609✔
4774
        pInfo->bins[k].percentage = pInfo->bins[k].count / (double)pInfo->totalCount;
9,245,566✔
4775
      } else {
4776
        pInfo->bins[k].percentage = 0;
59,532,043✔
4777
      }
4778
    }
4779
  }
4780

4781
  for (int32_t i = 0; i < pResInfo->numOfRes; ++i) {
82,556,045✔
4782
    int32_t len;
4783
    char    buf[512] = {0};
68,813,400✔
4784
    if (!pInfo->normalized) {
68,813,400✔
4785
      len = tsnprintf(varDataVal(buf), sizeof(buf) - VARSTR_HEADER_SIZE,
37,241✔
4786
                      "{\"lower_bin\":%g, \"upper_bin\":%g, \"count\":%" PRId64 "}", pInfo->bins[i].lower,
4787
                      pInfo->bins[i].upper, pInfo->bins[i].count);
4788
    } else {
4789
      len = tsnprintf(varDataVal(buf), sizeof(buf) - VARSTR_HEADER_SIZE,
68,776,159✔
4790
                      "{\"lower_bin\":%g, \"upper_bin\":%g, \"count\":%lf}", pInfo->bins[i].lower, pInfo->bins[i].upper,
4791
                      pInfo->bins[i].percentage);
4792
    }
4793
    varDataSetLen(buf, len);
68,812,426✔
4794
    code = colDataSetVal(pCol, currentRow, buf, false);
68,812,426✔
4795
    if (TSDB_CODE_SUCCESS != code) {
68,794,745!
4796
      return code;
×
4797
    }
4798
    currentRow++;
68,794,745✔
4799
  }
4800

4801
  return code;
13,742,645✔
4802
}
4803

4804
int32_t histogramPartialFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
2,209,072✔
4805
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
2,209,072✔
4806
  SHistoFuncInfo*      pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
2,209,072✔
4807
  int32_t              resultBytes = getHistogramInfoSize();
2,209,072✔
4808
  char*                res = taosMemoryCalloc(resultBytes + VARSTR_HEADER_SIZE, sizeof(char));
2,209,072!
4809

4810
  if (NULL == res) {
2,209,072!
4811
    return terrno;
×
4812
  }
4813
  (void)memcpy(varDataVal(res), pInfo, resultBytes);
2,209,072✔
4814
  varDataSetLen(res, resultBytes);
2,209,072✔
4815

4816
  int32_t          slotId = pCtx->pExpr->base.resSchema.slotId;
2,209,072✔
4817
  int32_t          code = TSDB_CODE_SUCCESS;
2,209,072✔
4818
  SColumnInfoData* pCol = taosArrayGet(pBlock->pDataBlock, slotId);
2,209,072✔
4819
  if (NULL == pCol) {
2,209,072!
4820
    code = terrno;
×
4821
    goto _exit;
×
4822
  }
4823
  code = colDataSetVal(pCol, pBlock->info.rows, res, false);
2,209,072✔
4824

4825
_exit:
2,209,072✔
4826
  taosMemoryFree(res);
2,209,072!
4827
  return code;
2,209,072✔
4828
}
4829

4830
int32_t histogramCombine(SqlFunctionCtx* pDestCtx, SqlFunctionCtx* pSourceCtx) {
×
4831
  SResultRowEntryInfo* pDResInfo = GET_RES_INFO(pDestCtx);
×
4832
  SHistoFuncInfo*      pDBuf = GET_ROWCELL_INTERBUF(pDResInfo);
×
4833

4834
  SResultRowEntryInfo* pSResInfo = GET_RES_INFO(pSourceCtx);
×
4835
  SHistoFuncInfo*      pSBuf = GET_ROWCELL_INTERBUF(pSResInfo);
×
4836

4837
  histogramTransferInfo(pSBuf, pDBuf);
×
4838
  pDResInfo->numOfRes = TMAX(pDResInfo->numOfRes, pSResInfo->numOfRes);
×
4839
  pDResInfo->isNullRes &= pSResInfo->isNullRes;
×
4840
  return TSDB_CODE_SUCCESS;
×
4841
}
4842

4843
int32_t getHLLInfoSize() { return (int32_t)sizeof(SHLLInfo); }
10,272✔
4844

4845
bool getHLLFuncEnv(SFunctionNode* UNUSED_PARAM(pFunc), SFuncExecEnv* pEnv) {
68,948✔
4846
  pEnv->calcMemSize = sizeof(SHLLInfo);
68,948✔
4847
  return true;
68,948✔
4848
}
4849

4850
static uint8_t hllCountNum(void* data, int32_t bytes, int32_t* buk) {
3,916,235✔
4851
  uint64_t hash = MurmurHash3_64(data, bytes);
3,916,235✔
4852
  int32_t  index = hash & HLL_BUCKET_MASK;
3,914,695✔
4853
  hash >>= HLL_BUCKET_BITS;
3,914,695✔
4854
  hash |= ((uint64_t)1 << HLL_DATA_BITS);
3,914,695✔
4855
  uint64_t bit = 1;
3,914,695✔
4856
  uint8_t  count = 1;
3,914,695✔
4857
  while ((hash & bit) == 0) {
7,964,074✔
4858
    count++;
4,049,379✔
4859
    bit <<= 1;
4,049,379✔
4860
  }
4861
  *buk = index;
3,914,695✔
4862
  return count;
3,914,695✔
4863
}
4864

4865
static void hllBucketHisto(uint8_t* buckets, int32_t* bucketHisto) {
258,795✔
4866
  uint64_t* word = (uint64_t*)buckets;
258,795✔
4867
  uint8_t*  bytes;
4868

4869
  for (int32_t j = 0; j < HLL_BUCKETS >> 3; j++) {
522,120,002✔
4870
    if (*word == 0) {
521,861,207✔
4871
      bucketHisto[0] += 8;
520,713,040✔
4872
    } else {
4873
      bytes = (uint8_t*)word;
1,148,167✔
4874
      bucketHisto[bytes[0]]++;
1,148,167✔
4875
      bucketHisto[bytes[1]]++;
1,148,167✔
4876
      bucketHisto[bytes[2]]++;
1,148,167✔
4877
      bucketHisto[bytes[3]]++;
1,148,167✔
4878
      bucketHisto[bytes[4]]++;
1,148,167✔
4879
      bucketHisto[bytes[5]]++;
1,148,167✔
4880
      bucketHisto[bytes[6]]++;
1,148,167✔
4881
      bucketHisto[bytes[7]]++;
1,148,167✔
4882
    }
4883
    word++;
521,861,207✔
4884
  }
4885
}
258,795✔
4886
static double hllTau(double x) {
258,784✔
4887
  if (x == 0. || x == 1.) return 0.;
258,784!
4888
  double zPrime;
4889
  double y = 1.0;
×
4890
  double z = 1 - x;
×
4891
  do {
4892
    x = sqrt(x);
×
4893
    zPrime = z;
×
4894
    y *= 0.5;
×
4895
    z -= pow(1 - x, 2) * y;
×
4896
  } while (zPrime != z);
×
4897
  return z / 3;
×
4898
}
4899

4900
static double hllSigma(double x) {
258,807✔
4901
  if (x == 1.0) return INFINITY;
258,807✔
4902
  double zPrime;
4903
  double y = 1;
237,876✔
4904
  double z = x;
237,876✔
4905
  do {
4906
    x *= x;
4,650,408✔
4907
    zPrime = z;
4,650,408✔
4908
    z += x * y;
4,650,408✔
4909
    y += y;
4,650,408✔
4910
  } while (zPrime != z);
4,650,408✔
4911
  return z;
237,876✔
4912
}
4913

4914
// estimate the cardinality, the algorithm refer this paper: "New cardinality estimation algorithms for HyperLogLog
4915
// sketches"
4916
static uint64_t hllCountCnt(uint8_t* buckets) {
258,764✔
4917
  double  m = HLL_BUCKETS;
258,764✔
4918
  int32_t buckethisto[64] = {0};
258,764✔
4919
  hllBucketHisto(buckets, buckethisto);
258,764✔
4920

4921
  double z = m * hllTau((m - buckethisto[HLL_DATA_BITS + 1]) / (double)m);
258,790✔
4922
  for (int j = HLL_DATA_BITS; j >= 1; --j) {
13,194,477✔
4923
    z += buckethisto[j];
12,935,670✔
4924
    z *= 0.5;
12,935,670✔
4925
  }
4926

4927
  z += m * hllSigma(buckethisto[0] / (double)m);
258,807✔
4928
  double E = (double)llroundl(HLL_ALPHA_INF * m * m / z);
258,811✔
4929

4930
  return (uint64_t)E;
258,811✔
4931
}
4932

4933
int32_t hllFunction(SqlFunctionCtx* pCtx) {
283,577✔
4934
  SHLLInfo* pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
283,577✔
4935

4936
  SInputColumnInfoData* pInput = &pCtx->input;
283,577✔
4937
  SColumnInfoData*      pCol = pInput->pData[0];
283,577✔
4938

4939
  int32_t type = pCol->info.type;
283,577✔
4940
  int32_t bytes = pCol->info.bytes;
283,577✔
4941

4942
  int32_t start = pInput->startRowIndex;
283,577✔
4943
  int32_t numOfRows = pInput->numOfRows;
283,577✔
4944

4945
  int32_t numOfElems = 0;
283,577✔
4946
  if (IS_NULL_TYPE(type)) {
283,577✔
4947
    goto _hll_over;
1,565✔
4948
  }
4949

4950
  for (int32_t i = start; i < numOfRows + start; ++i) {
4,898,060✔
4951
    if (pCol->hasNull && colDataIsNull_s(pCol, i)) {
6,194,570!
4952
      continue;
699,620✔
4953
    }
4954

4955
    numOfElems++;
3,919,016✔
4956

4957
    char* data = colDataGetData(pCol, i);
3,919,016!
4958
    if (IS_VAR_DATA_TYPE(type)) {
3,919,016!
4959
      bytes = varDataLen(data);
1,121,879✔
4960
      data = varDataVal(data);
1,121,879✔
4961
    }
4962

4963
    int32_t index = 0;
3,919,016✔
4964
    uint8_t count = hllCountNum(data, bytes, &index);
3,919,016✔
4965
    uint8_t oldcount = pInfo->buckets[index];
3,916,428✔
4966
    if (count > oldcount) {
3,916,428✔
4967
      pInfo->buckets[index] = count;
1,180,857✔
4968
    }
4969
  }
4970

4971
_hll_over:
279,424✔
4972
  pInfo->totalCount += numOfElems;
280,989✔
4973

4974
  if (pInfo->totalCount == 0 && !tsCountAlwaysReturnValue) {
280,989✔
4975
    SET_VAL(GET_RES_INFO(pCtx), 0, 1);
1,851✔
4976
  } else {
4977
    SET_VAL(GET_RES_INFO(pCtx), 1, 1);
279,138✔
4978
  }
4979

4980
  return TSDB_CODE_SUCCESS;
280,989✔
4981
}
4982

4983
static void hllTransferInfo(SHLLInfo* pInput, SHLLInfo* pOutput) {
10,551✔
4984
  for (int32_t k = 0; k < HLL_BUCKETS; ++k) {
168,702,142✔
4985
    if (pOutput->buckets[k] < pInput->buckets[k]) {
168,691,591✔
4986
      pOutput->buckets[k] = pInput->buckets[k];
201,079✔
4987
    }
4988
  }
4989
  pOutput->totalCount += pInput->totalCount;
10,551✔
4990
}
10,551✔
4991

4992
int32_t hllFunctionMerge(SqlFunctionCtx* pCtx) {
10,485✔
4993
  SInputColumnInfoData* pInput = &pCtx->input;
10,485✔
4994
  SColumnInfoData*      pCol = pInput->pData[0];
10,485✔
4995

4996
  if (IS_NULL_TYPE(pCol->info.type)) {
10,485!
4997
    SET_VAL(GET_RES_INFO(pCtx), 0, 1);
×
4998
    return TSDB_CODE_SUCCESS;
×
4999
  }
5000

5001
  if (pCol->info.type != TSDB_DATA_TYPE_BINARY) {
10,485!
5002
    return TSDB_CODE_SUCCESS;
×
5003
  }
5004

5005
  SHLLInfo* pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
10,485✔
5006

5007
  int32_t start = pInput->startRowIndex;
10,485✔
5008

5009
  for (int32_t i = start; i < start + pInput->numOfRows; ++i) {
21,035✔
5010
    if (colDataIsNull_s(pCol, i)) continue;
21,100!
5011
    char*     data = colDataGetData(pCol, i);
10,550!
5012
    SHLLInfo* pInputInfo = (SHLLInfo*)varDataVal(data);
10,550✔
5013
    hllTransferInfo(pInputInfo, pInfo);
10,550✔
5014
  }
5015

5016
  if (pInfo->totalCount == 0 && !tsCountAlwaysReturnValue) {
10,485✔
5017
    SET_VAL(GET_RES_INFO(pCtx), 0, 1);
3✔
5018
  } else {
5019
    SET_VAL(GET_RES_INFO(pCtx), 1, 1);
10,482✔
5020
  }
5021

5022
  return TSDB_CODE_SUCCESS;
10,485✔
5023
}
5024

5025
int32_t hllFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
258,763✔
5026
  SResultRowEntryInfo* pInfo = GET_RES_INFO(pCtx);
258,763✔
5027

5028
  SHLLInfo* pHllInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
258,763✔
5029
  pHllInfo->result = hllCountCnt(pHllInfo->buckets);
258,763✔
5030
  if (tsCountAlwaysReturnValue && pHllInfo->result == 0) {
258,813✔
5031
    pInfo->numOfRes = 1;
19,101✔
5032
  }
5033

5034
  return functionFinalize(pCtx, pBlock);
258,813✔
5035
}
5036

5037
int32_t hllPartialFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
10,273✔
5038
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
10,273✔
5039
  SHLLInfo*            pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
10,273✔
5040
  int32_t              resultBytes = getHLLInfoSize();
10,273✔
5041
  char*                res = taosMemoryCalloc(resultBytes + VARSTR_HEADER_SIZE, sizeof(char));
10,272!
5042

5043
  if (NULL == res) {
10,273!
5044
    return terrno;
×
5045
  }
5046
  (void)memcpy(varDataVal(res), pInfo, resultBytes);
10,273✔
5047
  varDataSetLen(res, resultBytes);
10,273✔
5048

5049
  int32_t          slotId = pCtx->pExpr->base.resSchema.slotId;
10,273✔
5050
  int32_t          code = TSDB_CODE_SUCCESS;
10,273✔
5051
  SColumnInfoData* pCol = taosArrayGet(pBlock->pDataBlock, slotId);
10,273✔
5052
  if (NULL == pCol) {
10,273!
5053
    code = terrno;
×
5054
    goto _exit;
×
5055
  }
5056

5057
  code = colDataSetVal(pCol, pBlock->info.rows, res, false);
10,273✔
5058

5059
_exit:
10,272✔
5060
  taosMemoryFree(res);
10,272!
5061
  return code;
10,272✔
5062
}
5063

5064
int32_t hllCombine(SqlFunctionCtx* pDestCtx, SqlFunctionCtx* pSourceCtx) {
1✔
5065
  SResultRowEntryInfo* pDResInfo = GET_RES_INFO(pDestCtx);
1✔
5066
  SHLLInfo*            pDBuf = GET_ROWCELL_INTERBUF(pDResInfo);
1✔
5067

5068
  SResultRowEntryInfo* pSResInfo = GET_RES_INFO(pSourceCtx);
1✔
5069
  SHLLInfo*            pSBuf = GET_ROWCELL_INTERBUF(pSResInfo);
1✔
5070

5071
  hllTransferInfo(pSBuf, pDBuf);
1✔
5072
  pDResInfo->numOfRes = TMAX(pDResInfo->numOfRes, pSResInfo->numOfRes);
1✔
5073
  pDResInfo->isNullRes &= pSResInfo->isNullRes;
1✔
5074
  return TSDB_CODE_SUCCESS;
1✔
5075
}
5076

5077
bool getStateFuncEnv(SFunctionNode* UNUSED_PARAM(pFunc), SFuncExecEnv* pEnv) {
22,354✔
5078
  pEnv->calcMemSize = sizeof(SStateInfo);
22,354✔
5079
  return true;
22,354✔
5080
}
5081

5082
static int8_t getStateOpType(char* opStr) {
142,912✔
5083
  int8_t opType;
5084
  if (strncasecmp(opStr, "LT", 2) == 0) {
142,912✔
5085
    opType = STATE_OPER_LT;
26,095✔
5086
  } else if (strncasecmp(opStr, "GT", 2) == 0) {
116,817✔
5087
    opType = STATE_OPER_GT;
3,126✔
5088
  } else if (strncasecmp(opStr, "LE", 2) == 0) {
113,691✔
5089
    opType = STATE_OPER_LE;
984✔
5090
  } else if (strncasecmp(opStr, "GE", 2) == 0) {
112,707✔
5091
    opType = STATE_OPER_GE;
992✔
5092
  } else if (strncasecmp(opStr, "NE", 2) == 0) {
111,715✔
5093
    opType = STATE_OPER_NE;
109,788✔
5094
  } else if (strncasecmp(opStr, "EQ", 2) == 0) {
1,927!
5095
    opType = STATE_OPER_EQ;
1,927✔
5096
  } else {
5097
    opType = STATE_OPER_INVALID;
×
5098
  }
5099

5100
  return opType;
142,912✔
5101
}
5102

5103
static bool checkStateOp(int8_t op, SColumnInfoData* pCol, int32_t index, SVariant param) {
34,937,592✔
5104
  char* data = colDataGetData(pCol, index);
34,937,592!
5105
  switch (pCol->info.type) {
34,937,592!
5106
    case TSDB_DATA_TYPE_TINYINT: {
95,712✔
5107
      int8_t v = *(int8_t*)data;
95,712✔
5108
      STATE_COMP(op, v, param);
95,712!
5109
      break;
×
5110
    }
5111
    case TSDB_DATA_TYPE_UTINYINT: {
5,760✔
5112
      uint8_t v = *(uint8_t*)data;
5,760✔
5113
      STATE_COMP(op, v, param);
5,760!
5114
      break;
×
5115
    }
5116
    case TSDB_DATA_TYPE_SMALLINT: {
148,724✔
5117
      int16_t v = *(int16_t*)data;
148,724✔
5118
      STATE_COMP(op, v, param);
148,724!
5119
      break;
×
5120
    }
5121
    case TSDB_DATA_TYPE_USMALLINT: {
5,760✔
5122
      uint16_t v = *(uint16_t*)data;
5,760✔
5123
      STATE_COMP(op, v, param);
5,760!
5124
      break;
×
5125
    }
5126
    case TSDB_DATA_TYPE_INT: {
125,670✔
5127
      int32_t v = *(int32_t*)data;
125,670✔
5128
      STATE_COMP(op, v, param);
125,670!
5129
      break;
×
5130
    }
5131
    case TSDB_DATA_TYPE_UINT: {
5,760✔
5132
      uint32_t v = *(uint32_t*)data;
5,760✔
5133
      STATE_COMP(op, v, param);
5,760!
5134
      break;
×
5135
    }
5136
    case TSDB_DATA_TYPE_BIGINT: {
5,126,478✔
5137
      int64_t v = *(int64_t*)data;
5,126,478✔
5138
      STATE_COMP(op, v, param);
5,126,478!
5139
      break;
×
5140
    }
5141
    case TSDB_DATA_TYPE_UBIGINT: {
5,760✔
5142
      uint64_t v = *(uint64_t*)data;
5,760✔
5143
      STATE_COMP(op, v, param);
5,760!
5144
      break;
×
5145
    }
5146
    case TSDB_DATA_TYPE_FLOAT: {
71,024✔
5147
      float v = *(float*)data;
71,024✔
5148
      STATE_COMP(op, v, param);
71,024!
5149
      break;
×
5150
    }
5151
    case TSDB_DATA_TYPE_DOUBLE: {
29,348,842✔
5152
      double v = *(double*)data;
29,348,842✔
5153
      STATE_COMP(op, v, param);
29,348,842!
5154
      break;
×
5155
    }
5156
    default: {
×
5157
      return false;
×
5158
    }
5159
  }
5160
  return false;
×
5161
}
5162

5163
int32_t stateCountFunction(SqlFunctionCtx* pCtx) {
105,201✔
5164
  int32_t              code = TSDB_CODE_SUCCESS;
105,201✔
5165
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
105,201✔
5166
  SStateInfo*          pInfo = GET_ROWCELL_INTERBUF(pResInfo);
105,201✔
5167

5168
  SInputColumnInfoData* pInput = &pCtx->input;
105,201✔
5169
  TSKEY*                tsList = (int64_t*)pInput->pPTS->pData;
105,201✔
5170

5171
  SColumnInfoData* pInputCol = pInput->pData[0];
105,201✔
5172

5173
  int32_t          numOfElems = 0;
105,201✔
5174
  SColumnInfoData* pOutput = (SColumnInfoData*)pCtx->pOutput;
105,201✔
5175

5176
  int8_t op = getStateOpType(varDataVal(pCtx->param[1].param.pz));
105,201✔
5177
  if (STATE_OPER_INVALID == op) {
105,201!
5178
    return 0;
×
5179
  }
5180

5181
  for (int32_t i = pInput->startRowIndex; i < pInput->numOfRows + pInput->startRowIndex; i += 1) {
28,020,125✔
5182
    if (pInfo->isPrevTsSet == true && tsList[i] == pInfo->prevTs) {
27,914,924!
5183
      return TSDB_CODE_FUNC_DUP_TIMESTAMP;
×
5184
    } else {
5185
      pInfo->prevTs = tsList[i];
27,914,924✔
5186
    }
5187

5188
    pInfo->isPrevTsSet = true;
27,914,924✔
5189
    numOfElems++;
27,914,924✔
5190

5191
    if (colDataIsNull_f(pInputCol->nullbitmap, i)) {
27,914,924✔
5192
      colDataSetNULL(pOutput, i);
220,224!
5193
      // handle selectivity
5194
      if (pCtx->subsidiaries.num > 0) {
220,224✔
5195
        code = appendSelectivityValue(pCtx, i, pCtx->offset + numOfElems - 1);
36✔
5196
        if (TSDB_CODE_SUCCESS != code) {
36!
5197
          return code;
×
5198
        }
5199
      }
5200
      continue;
220,224✔
5201
    }
5202

5203
    bool ret = checkStateOp(op, pInputCol, i, pCtx->param[2].param);
27,694,700✔
5204

5205
    int64_t output = -1;
27,694,700✔
5206
    if (ret) {
27,694,700✔
5207
      output = ++pInfo->count;
25,143,799✔
5208
    } else {
5209
      pInfo->count = 0;
2,550,901✔
5210
    }
5211
    code = colDataSetVal(pOutput, pCtx->offset + numOfElems - 1, (char*)&output, false);
27,694,700✔
5212
    if (TSDB_CODE_SUCCESS != code) {
27,694,700!
5213
      return code;
×
5214
    }
5215

5216
    // handle selectivity
5217
    if (pCtx->subsidiaries.num > 0) {
27,694,700✔
5218
      code = appendSelectivityValue(pCtx, i, pCtx->offset + numOfElems - 1);
16,456,432✔
5219
      if (TSDB_CODE_SUCCESS != code) {
16,456,432!
5220
        return code;
×
5221
      }
5222
    }
5223
  }
5224

5225
  pResInfo->numOfRes = numOfElems;
105,201✔
5226
  return TSDB_CODE_SUCCESS;
105,201✔
5227
}
5228

5229
int32_t stateDurationFunction(SqlFunctionCtx* pCtx) {
37,711✔
5230
  int32_t              code = TSDB_CODE_SUCCESS;
37,711✔
5231
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
37,711✔
5232
  SStateInfo*          pInfo = GET_ROWCELL_INTERBUF(pResInfo);
37,711✔
5233

5234
  SInputColumnInfoData* pInput = &pCtx->input;
37,711✔
5235
  TSKEY*                tsList = (int64_t*)pInput->pPTS->pData;
37,711✔
5236

5237
  SColumnInfoData* pInputCol = pInput->pData[0];
37,711✔
5238

5239
  int32_t          numOfElems = 0;
37,711✔
5240
  SColumnInfoData* pOutput = (SColumnInfoData*)pCtx->pOutput;
37,711✔
5241

5242
  // TODO: process timeUnit for different db precisions
5243
  int32_t timeUnit = 1;
37,711✔
5244
  if (pCtx->numOfParams == 5) {  // TODO: param number incorrect
37,711✔
5245
    timeUnit = pCtx->param[3].param.i;
35,751✔
5246
  }
5247

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

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

5260
    pInfo->isPrevTsSet = true;
7,466,484✔
5261
    numOfElems++;
7,466,484✔
5262

5263
    if (colDataIsNull_f(pInputCol->nullbitmap, i)) {
7,466,484✔
5264
      colDataSetNULL(pOutput, i);
223,540!
5265
      // handle selectivity
5266
      if (pCtx->subsidiaries.num > 0) {
223,540✔
5267
        code = appendSelectivityValue(pCtx, i, pCtx->offset + numOfElems - 1);
44✔
5268
        if (TSDB_CODE_SUCCESS != code) {
44!
5269
          return code;
×
5270
        }
5271
      }
5272
      continue;
223,540✔
5273
    }
5274

5275
    bool    ret = checkStateOp(op, pInputCol, i, pCtx->param[2].param);
7,242,944✔
5276
    int64_t output = -1;
7,242,876✔
5277
    if (ret) {
7,242,876✔
5278
      if (pInfo->durationStart == 0) {
7,072,633✔
5279
        output = 0;
57,945✔
5280
        pInfo->durationStart = tsList[i];
57,945✔
5281
      } else {
5282
        output = (tsList[i] - pInfo->durationStart) / timeUnit;
7,014,688✔
5283
      }
5284
    } else {
5285
      pInfo->durationStart = 0;
170,243✔
5286
    }
5287
    code = colDataSetVal(pOutput, pCtx->offset + numOfElems - 1, (char*)&output, false);
7,242,876✔
5288
    if (TSDB_CODE_SUCCESS != code) {
7,243,005!
5289
      return code;
×
5290
    }
5291

5292
    // handle selectivity
5293
    if (pCtx->subsidiaries.num > 0) {
7,243,005✔
5294
      code = appendSelectivityValue(pCtx, i, pCtx->offset + numOfElems - 1);
3,596,912✔
5295
      if (TSDB_CODE_SUCCESS != code) {
3,596,912!
5296
        return code;
×
5297
      }
5298
    }
5299
  }
5300

5301
  pResInfo->numOfRes = numOfElems;
37,772✔
5302
  return TSDB_CODE_SUCCESS;
37,772✔
5303
}
5304

5305
bool getCsumFuncEnv(SFunctionNode* UNUSED_PARAM(pFunc), SFuncExecEnv* pEnv) {
15,601✔
5306
  pEnv->calcMemSize = sizeof(SSumRes);
15,601✔
5307
  return true;
15,601✔
5308
}
5309

5310
int32_t csumFunction(SqlFunctionCtx* pCtx) {
25,856✔
5311
  int32_t              code = TSDB_CODE_SUCCESS;
25,856✔
5312
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
25,856✔
5313
  SSumRes*             pSumRes = GET_ROWCELL_INTERBUF(pResInfo);
25,856✔
5314

5315
  SInputColumnInfoData* pInput = &pCtx->input;
25,856✔
5316
  TSKEY*                tsList = (int64_t*)pInput->pPTS->pData;
25,856✔
5317

5318
  SColumnInfoData* pInputCol = pInput->pData[0];
25,856✔
5319
  SColumnInfoData* pOutput = (SColumnInfoData*)pCtx->pOutput;
25,856✔
5320

5321
  int32_t numOfElems = 0;
25,856✔
5322
  int32_t type = pInputCol->info.type;
25,856✔
5323
  int32_t startOffset = pCtx->offset;
25,856✔
5324
  for (int32_t i = pInput->startRowIndex; i < pInput->numOfRows + pInput->startRowIndex; i += 1) {
3,986,754✔
5325
    if (pSumRes->isPrevTsSet == true && tsList[i] == pSumRes->prevTs) {
3,960,680✔
5326
      return TSDB_CODE_FUNC_DUP_TIMESTAMP;
18✔
5327
    } else {
5328
      pSumRes->prevTs = tsList[i];
3,960,662✔
5329
    }
5330
    pSumRes->isPrevTsSet = true;
3,960,662✔
5331

5332
    int32_t pos = startOffset + numOfElems;
3,960,662✔
5333
    if (colDataIsNull_f(pInputCol->nullbitmap, i)) {
3,960,662✔
5334
      // colDataSetNULL(pOutput, i);
5335
      continue;
418,624✔
5336
    }
5337

5338
    char* data = colDataGetData(pInputCol, i);
3,542,038!
5339
    if (IS_SIGNED_NUMERIC_TYPE(type)) {
5,924,818✔
5340
      int64_t v;
5341
      GET_TYPED_DATA(v, int64_t, type, data);
2,382,544!
5342
      pSumRes->isum += v;
2,382,544✔
5343
      code = colDataSetVal(pOutput, pos, (char*)&pSumRes->isum, false);
2,382,544✔
5344
      if (TSDB_CODE_SUCCESS != code) {
2,382,780!
5345
        return code;
×
5346
      }
5347
    } else if (IS_UNSIGNED_NUMERIC_TYPE(type)) {
1,160,174!
5348
      uint64_t v;
5349
      GET_TYPED_DATA(v, uint64_t, type, data);
680!
5350
      pSumRes->usum += v;
680✔
5351
      code = colDataSetVal(pOutput, pos, (char*)&pSumRes->usum, false);
680✔
5352
      if (TSDB_CODE_SUCCESS != code) {
680!
5353
        return code;
×
5354
      }
5355
    } else if (IS_FLOAT_TYPE(type)) {
1,158,814!
5356
      double v;
5357
      GET_TYPED_DATA(v, double, type, data);
1,158,852!
5358
      pSumRes->dsum += v;
1,158,852✔
5359
      // check for overflow
5360
      if (isinf(pSumRes->dsum) || isnan(pSumRes->dsum)) {
1,158,852!
5361
        colDataSetNULL(pOutput, pos);
8!
5362
      } else {
5363
        code = colDataSetVal(pOutput, pos, (char*)&pSumRes->dsum, false);
1,158,844✔
5364
        if (TSDB_CODE_SUCCESS != code) {
1,158,844!
5365
          return code;
×
5366
        }
5367
      }
5368
    }
5369

5370
    // handle selectivity
5371
    if (pCtx->subsidiaries.num > 0) {
3,542,274✔
5372
      code = appendSelectivityValue(pCtx, i, pos);
1,990,338✔
5373
      if (TSDB_CODE_SUCCESS != code) {
1,990,338!
5374
        return code;
×
5375
      }
5376
    }
5377

5378
    numOfElems++;
3,542,274✔
5379
  }
5380

5381
  pResInfo->numOfRes = numOfElems;
26,074✔
5382
  return TSDB_CODE_SUCCESS;
26,074✔
5383
}
5384

5385
bool getMavgFuncEnv(SFunctionNode* UNUSED_PARAM(pFunc), SFuncExecEnv* pEnv) {
13,638✔
5386
  pEnv->calcMemSize = sizeof(SMavgInfo) + MAVG_MAX_POINTS_NUM * sizeof(double);
13,638✔
5387
  return true;
13,638✔
5388
}
5389

5390
int32_t mavgFunctionSetup(SqlFunctionCtx* pCtx, SResultRowEntryInfo* pResultInfo) {
252,585✔
5391
  if (pResultInfo->initialized) {
252,585✔
5392
    return TSDB_CODE_SUCCESS;
238,256✔
5393
  }
5394
  if (TSDB_CODE_SUCCESS != functionSetup(pCtx, pResultInfo)) {
14,329!
5395
    return TSDB_CODE_FUNC_SETUP_ERROR;
×
5396
  }
5397

5398
  SMavgInfo* pInfo = GET_ROWCELL_INTERBUF(pResultInfo);
14,328✔
5399
  pInfo->pos = 0;
14,328✔
5400
  pInfo->sum = 0;
14,328✔
5401
  pInfo->prevTs = -1;
14,328✔
5402
  pInfo->isPrevTsSet = false;
14,328✔
5403
  pInfo->numOfPoints = pCtx->param[1].param.i;
14,328✔
5404
  if (pInfo->numOfPoints < 1 || pInfo->numOfPoints > MAVG_MAX_POINTS_NUM) {
14,328!
5405
    return TSDB_CODE_FUNC_FUNTION_PARA_VALUE;
×
5406
  }
5407
  pInfo->pointsMeet = false;
14,331✔
5408

5409
  return TSDB_CODE_SUCCESS;
14,331✔
5410
}
5411

5412
int32_t mavgFunction(SqlFunctionCtx* pCtx) {
238,946✔
5413
  int32_t              code = TSDB_CODE_SUCCESS;
238,946✔
5414
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
238,946✔
5415
  SMavgInfo*           pInfo = GET_ROWCELL_INTERBUF(pResInfo);
238,946✔
5416

5417
  SInputColumnInfoData* pInput = &pCtx->input;
238,946✔
5418
  TSKEY*                tsList = (int64_t*)pInput->pPTS->pData;
238,946✔
5419

5420
  SColumnInfoData* pInputCol = pInput->pData[0];
238,946✔
5421
  SColumnInfoData* pTsOutput = pCtx->pTsOutput;
238,946✔
5422
  SColumnInfoData* pOutput = (SColumnInfoData*)pCtx->pOutput;
238,946✔
5423

5424
  int32_t numOfElems = 0;
238,946✔
5425
  int32_t type = pInputCol->info.type;
238,946✔
5426
  int32_t startOffset = pCtx->offset;
238,946✔
5427
  for (int32_t i = pInput->startRowIndex; i < pInput->numOfRows + pInput->startRowIndex; i += 1) {
57,917,338✔
5428
    if (pInfo->isPrevTsSet == true && tsList[i] == pInfo->prevTs) {
57,678,392!
5429
      return TSDB_CODE_FUNC_DUP_TIMESTAMP;
×
5430
    } else {
5431
      pInfo->prevTs = tsList[i];
57,678,392✔
5432
    }
5433
    pInfo->isPrevTsSet = true;
57,678,392✔
5434

5435
    int32_t pos = startOffset + numOfElems;
57,678,392✔
5436
    if (colDataIsNull_f(pInputCol->nullbitmap, i)) {
57,678,392✔
5437
      // colDataSetNULL(pOutput, i);
5438
      continue;
373,941✔
5439
    }
5440

5441
    char*  data = colDataGetData(pInputCol, i);
57,304,451!
5442
    double v;
5443
    GET_TYPED_DATA(v, double, type, data);
57,304,451!
5444

5445
    if (!pInfo->pointsMeet && (pInfo->pos < pInfo->numOfPoints - 1)) {
57,304,451✔
5446
      pInfo->points[pInfo->pos] = v;
3,592,071✔
5447
      pInfo->sum += v;
3,592,071✔
5448
    } else {
5449
      if (!pInfo->pointsMeet && (pInfo->pos == pInfo->numOfPoints - 1)) {
53,712,380!
5450
        pInfo->sum += v;
10,822✔
5451
        pInfo->pointsMeet = true;
10,822✔
5452
      } else {
5453
        pInfo->sum = pInfo->sum + v - pInfo->points[pInfo->pos];
53,701,558✔
5454
      }
5455

5456
      pInfo->points[pInfo->pos] = v;
53,712,380✔
5457
      double result = pInfo->sum / pInfo->numOfPoints;
53,712,380✔
5458
      // check for overflow
5459
      if (isinf(result) || isnan(result)) {
53,712,380!
5460
        colDataSetNULL(pOutput, pos);
×
5461
      } else {
5462
        code = colDataSetVal(pOutput, pos, (char*)&result, false);
53,712,380✔
5463
        if (TSDB_CODE_SUCCESS != code) {
53,712,380!
5464
          return code;
×
5465
        }
5466
      }
5467

5468
      // handle selectivity
5469
      if (pCtx->subsidiaries.num > 0) {
53,712,380✔
5470
        code = appendSelectivityValue(pCtx, i, pos);
33,885,083✔
5471
        if (TSDB_CODE_SUCCESS != code) {
33,885,083!
5472
          return code;
×
5473
        }
5474
      }
5475

5476
      numOfElems++;
53,712,380✔
5477
    }
5478

5479
    pInfo->pos++;
57,304,451✔
5480
    if (pInfo->pos == pInfo->numOfPoints) {
57,304,451✔
5481
      pInfo->pos = 0;
416,671✔
5482
    }
5483
  }
5484

5485
  pResInfo->numOfRes = numOfElems;
238,946✔
5486
  return TSDB_CODE_SUCCESS;
238,946✔
5487
}
5488

5489
static SSampleInfo* getSampleOutputInfo(SqlFunctionCtx* pCtx) {
13,653,365✔
5490
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
13,653,365✔
5491
  SSampleInfo*         pInfo = GET_ROWCELL_INTERBUF(pResInfo);
13,653,365✔
5492

5493
  pInfo->data = (char*)pInfo + sizeof(SSampleInfo);
13,653,365✔
5494
  pInfo->tuplePos = (STuplePos*)((char*)pInfo + sizeof(SSampleInfo) + pInfo->samples * pInfo->colBytes);
13,653,365✔
5495

5496
  return pInfo;
13,653,365✔
5497
}
5498

5499
bool getSampleFuncEnv(SFunctionNode* pFunc, SFuncExecEnv* pEnv) {
27,032✔
5500
  SColumnNode* pCol = (SColumnNode*)nodesListGetNode(pFunc->pParameterList, 0);
27,032✔
5501
  SValueNode*  pVal = (SValueNode*)nodesListGetNode(pFunc->pParameterList, 1);
27,041✔
5502
  int32_t      numOfSamples = pVal->datum.i;
27,045✔
5503
  pEnv->calcMemSize = sizeof(SSampleInfo) + numOfSamples * (pCol->node.resType.bytes + sizeof(STuplePos));
27,045✔
5504
  return true;
27,045✔
5505
}
5506

5507
int32_t sampleFunctionSetup(SqlFunctionCtx* pCtx, SResultRowEntryInfo* pResultInfo) {
6,836,930✔
5508
  if (pResultInfo->initialized) {
6,836,930!
5509
    return TSDB_CODE_SUCCESS;
×
5510
  }
5511
  if (TSDB_CODE_SUCCESS != functionSetup(pCtx, pResultInfo)) {
6,836,930!
5512
    return TSDB_CODE_FUNC_SETUP_ERROR;
×
5513
  }
5514

5515
  taosSeedRand(taosSafeRand());
6,836,929✔
5516

5517
  SSampleInfo* pInfo = GET_ROWCELL_INTERBUF(pResultInfo);
6,836,932✔
5518
  pInfo->samples = pCtx->param[1].param.i;
6,836,932✔
5519
  pInfo->totalPoints = 0;
6,836,932✔
5520
  pInfo->numSampled = 0;
6,836,932✔
5521
  pInfo->colType = pCtx->resDataInfo.type;
6,836,932✔
5522
  pInfo->colBytes = pCtx->resDataInfo.bytes;
6,836,932✔
5523
  pInfo->nullTuplePos.pageId = -1;
6,836,932✔
5524
  pInfo->nullTupleSaved = false;
6,836,932✔
5525
  pInfo->data = (char*)pInfo + sizeof(SSampleInfo);
6,836,932✔
5526
  pInfo->tuplePos = (STuplePos*)((char*)pInfo + sizeof(SSampleInfo) + pInfo->samples * pInfo->colBytes);
6,836,932✔
5527

5528
  return TSDB_CODE_SUCCESS;
6,836,932✔
5529
}
5530

5531
static void sampleAssignResult(SSampleInfo* pInfo, char* data, int32_t index) {
13,199,544✔
5532
  assignVal(pInfo->data + index * pInfo->colBytes, data, pInfo->colBytes, pInfo->colType);
13,199,544✔
5533
}
13,199,587✔
5534

5535
static int32_t doReservoirSample(SqlFunctionCtx* pCtx, SSampleInfo* pInfo, char* data, int32_t index) {
15,854,632✔
5536
  pInfo->totalPoints++;
15,854,632✔
5537
  if (pInfo->numSampled < pInfo->samples) {
15,854,632✔
5538
    sampleAssignResult(pInfo, data, pInfo->numSampled);
11,311,885✔
5539
    if (pCtx->subsidiaries.num > 0) {
11,312,005✔
5540
      int32_t code = saveTupleData(pCtx, index, pCtx->pSrcBlock, &pInfo->tuplePos[pInfo->numSampled]);
806,786✔
5541
      if (code != TSDB_CODE_SUCCESS) {
806,652!
5542
        return code;
×
5543
      }
5544
    }
5545
    pInfo->numSampled++;
11,311,871✔
5546
  } else {
5547
    int32_t j = taosRand() % (pInfo->totalPoints);
4,542,747✔
5548
    if (j < pInfo->samples) {
4,545,427✔
5549
      sampleAssignResult(pInfo, data, j);
1,888,003✔
5550
      if (pCtx->subsidiaries.num > 0) {
1,887,966✔
5551
        int32_t code = updateTupleData(pCtx, index, pCtx->pSrcBlock, &pInfo->tuplePos[j]);
621,292✔
5552
        if (code != TSDB_CODE_SUCCESS) {
619,115!
5553
          return code;
×
5554
        }
5555
      }
5556
    }
5557
  }
5558

5559
  return TSDB_CODE_SUCCESS;
15,855,084✔
5560
}
5561

5562
int32_t sampleFunction(SqlFunctionCtx* pCtx) {
6,935,943✔
5563
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
6,935,943✔
5564
  SSampleInfo*         pInfo = getSampleOutputInfo(pCtx);
6,935,943✔
5565

5566
  SInputColumnInfoData* pInput = &pCtx->input;
6,935,942✔
5567

5568
  SColumnInfoData* pInputCol = pInput->pData[0];
6,935,942✔
5569
  for (int32_t i = pInput->startRowIndex; i < pInput->numOfRows + pInput->startRowIndex; i += 1) {
23,220,759✔
5570
    if (colDataIsNull_s(pInputCol, i)) {
32,568,606✔
5571
      continue;
429,959✔
5572
    }
5573

5574
    char*   data = colDataGetData(pInputCol, i);
15,854,344!
5575
    int32_t code = doReservoirSample(pCtx, pInfo, data, i);
15,854,344✔
5576
    if (code != TSDB_CODE_SUCCESS) {
15,854,858!
5577
      return code;
×
5578
    }
5579
  }
5580

5581
  if (pInfo->numSampled == 0 && pCtx->subsidiaries.num > 0 && !pInfo->nullTupleSaved) {
6,936,456✔
5582
    int32_t code = saveTupleData(pCtx, pInput->startRowIndex, pCtx->pSrcBlock, &pInfo->nullTuplePos);
20✔
5583
    if (code != TSDB_CODE_SUCCESS) {
20!
5584
      return code;
×
5585
    }
5586
    pInfo->nullTupleSaved = true;
20✔
5587
  }
5588

5589
  SET_VAL(pResInfo, pInfo->numSampled, pInfo->numSampled);
6,936,456✔
5590
  return TSDB_CODE_SUCCESS;
6,936,456✔
5591
}
5592

5593
int32_t sampleFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
6,717,427✔
5594
  int32_t              code = TSDB_CODE_SUCCESS;
6,717,427✔
5595
  SResultRowEntryInfo* pEntryInfo = GET_RES_INFO(pCtx);
6,717,427✔
5596

5597
  SSampleInfo* pInfo = getSampleOutputInfo(pCtx);
6,717,427✔
5598
  pEntryInfo->complete = true;
6,717,427✔
5599

5600
  int32_t          slotId = pCtx->pExpr->base.resSchema.slotId;
6,717,427✔
5601
  SColumnInfoData* pCol = taosArrayGet(pBlock->pDataBlock, slotId);
6,717,427✔
5602
  if (NULL == pCol) {
6,717,426!
5603
    return TSDB_CODE_OUT_OF_RANGE;
×
5604
  }
5605

5606
  int32_t currentRow = pBlock->info.rows;
6,717,426✔
5607
  if (pInfo->numSampled == 0) {
6,717,426✔
5608
    colDataSetNULL(pCol, currentRow);
2,508✔
5609
    code = setSelectivityValue(pCtx, pBlock, &pInfo->nullTuplePos, currentRow);
2,508✔
5610
    return code;
2,508✔
5611
  }
5612
  for (int32_t i = 0; i < pInfo->numSampled; ++i) {
17,884,944✔
5613
    code = colDataSetVal(pCol, currentRow + i, pInfo->data + i * pInfo->colBytes, false);
11,170,125✔
5614
    if (TSDB_CODE_SUCCESS != code) {
11,170,425!
5615
      return code;
×
5616
    }
5617
    code = setSelectivityValue(pCtx, pBlock, &pInfo->tuplePos[i], currentRow + i);
11,170,425✔
5618
    if (TSDB_CODE_SUCCESS != code) {
11,170,026!
5619
      return code;
×
5620
    }
5621
  }
5622

5623
  return code;
6,714,819✔
5624
}
5625

5626
bool getTailFuncEnv(SFunctionNode* pFunc, SFuncExecEnv* pEnv) {
×
5627
#if 0
5628
  SColumnNode* pCol = (SColumnNode*)nodesListGetNode(pFunc->pParameterList, 0);
5629
  SValueNode*  pVal = (SValueNode*)nodesListGetNode(pFunc->pParameterList, 1);
5630
  int32_t      numOfPoints = pVal->datum.i;
5631
  pEnv->calcMemSize = sizeof(STailInfo) + numOfPoints * (POINTER_BYTES + sizeof(STailItem) + pCol->node.resType.bytes);
5632
#endif
5633
  return true;
×
5634
}
5635

5636
int32_t tailFunctionSetup(SqlFunctionCtx* pCtx, SResultRowEntryInfo* pResultInfo) {
×
5637
#if 0
5638
  if (!functionSetup(pCtx, pResultInfo)) {
5639
    return false;
5640
  }
5641

5642
  STailInfo* pInfo = GET_ROWCELL_INTERBUF(pResultInfo);
5643
  pInfo->numAdded = 0;
5644
  pInfo->numOfPoints = pCtx->param[1].param.i;
5645
  if (pCtx->numOfParams == 4) {
5646
    pInfo->offset = pCtx->param[2].param.i;
5647
  } else {
5648
    pInfo->offset = 0;
5649
  }
5650
  pInfo->colType = pCtx->resDataInfo.type;
5651
  pInfo->colBytes = pCtx->resDataInfo.bytes;
5652
  if ((pInfo->numOfPoints < 1 || pInfo->numOfPoints > TAIL_MAX_POINTS_NUM) ||
5653
      (pInfo->numOfPoints < 0 || pInfo->numOfPoints > TAIL_MAX_OFFSET)) {
5654
    return false;
5655
  }
5656

5657
  pInfo->pItems = (STailItem**)((char*)pInfo + sizeof(STailInfo));
5658
  char* pItem = (char*)pInfo->pItems + pInfo->numOfPoints * POINTER_BYTES;
5659

5660
  size_t unitSize = sizeof(STailItem) + pInfo->colBytes;
5661
  for (int32_t i = 0; i < pInfo->numOfPoints; ++i) {
5662
    pInfo->pItems[i] = (STailItem*)(pItem + i * unitSize);
5663
    pInfo->pItems[i]->isNull = false;
5664
  }
5665
#endif
5666

5667
  return TSDB_CODE_SUCCESS;
×
5668
}
5669

5670
static void tailAssignResult(STailItem* pItem, char* data, int32_t colBytes, TSKEY ts, bool isNull) {
×
5671
#if 0
5672
  pItem->timestamp = ts;
5673
  if (isNull) {
5674
    pItem->isNull = true;
5675
  } else {
5676
    pItem->isNull = false;
5677
    memcpy(pItem->data, data, colBytes);
5678
  }
5679
#endif
5680
}
×
5681

5682
#if 0
5683
static int32_t tailCompFn(const void* p1, const void* p2, const void* param) {
5684
  STailItem* d1 = *(STailItem**)p1;
5685
  STailItem* d2 = *(STailItem**)p2;
5686
  return compareInt64Val(&d1->timestamp, &d2->timestamp);
5687
}
5688

5689
static void doTailAdd(STailInfo* pInfo, char* data, TSKEY ts, bool isNull) {
5690
  STailItem** pList = pInfo->pItems;
5691
  if (pInfo->numAdded < pInfo->numOfPoints) {
5692
    tailAssignResult(pList[pInfo->numAdded], data, pInfo->colBytes, ts, isNull);
5693
    taosheapsort((void*)pList, sizeof(STailItem**), pInfo->numAdded + 1, NULL, tailCompFn, 0);
5694
    pInfo->numAdded++;
5695
  } else if (pList[0]->timestamp < ts) {
5696
    tailAssignResult(pList[0], data, pInfo->colBytes, ts, isNull);
5697
    taosheapadjust((void*)pList, sizeof(STailItem**), 0, pInfo->numOfPoints - 1, NULL, tailCompFn, NULL, 0);
5698
  }
5699
}
5700
#endif
5701

5702
int32_t tailFunction(SqlFunctionCtx* pCtx) {
×
5703
#if 0
5704
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
5705
  STailInfo*           pInfo = GET_ROWCELL_INTERBUF(pResInfo);
5706

5707
  SInputColumnInfoData* pInput = &pCtx->input;
5708
  TSKEY*                tsList = (int64_t*)pInput->pPTS->pData;
5709

5710
  SColumnInfoData* pInputCol = pInput->pData[0];
5711
  SColumnInfoData* pOutput = (SColumnInfoData*)pCtx->pOutput;
5712

5713
  int32_t startOffset = pCtx->offset;
5714
  if (pInfo->offset >= pInput->numOfRows) {
5715
    return 0;
5716
  } else {
5717
    pInfo->numOfPoints = TMIN(pInfo->numOfPoints, pInput->numOfRows - pInfo->offset);
5718
  }
5719
  for (int32_t i = pInput->startRowIndex; i < pInput->numOfRows + pInput->startRowIndex - pInfo->offset; i += 1) {
5720
    char* data = colDataGetData(pInputCol, i);
5721
    doTailAdd(pInfo, data, tsList[i], colDataIsNull_s(pInputCol, i));
5722
  }
5723

5724
  taosqsort(pInfo->pItems, pInfo->numOfPoints, POINTER_BYTES, NULL, tailCompFn);
5725

5726
  for (int32_t i = 0; i < pInfo->numOfPoints; ++i) {
5727
    int32_t    pos = startOffset + i;
5728
    STailItem* pItem = pInfo->pItems[i];
5729
    if (pItem->isNull) {
5730
      colDataSetNULL(pOutput, pos);
5731
    } else {
5732
      colDataSetVal(pOutput, pos, pItem->data, false);
5733
    }
5734
  }
5735

5736
  return pInfo->numOfPoints;
5737
#endif
5738
  return 0;
×
5739
}
5740

5741
int32_t tailFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
×
5742
#if 0
5743
  SResultRowEntryInfo* pEntryInfo = GET_RES_INFO(pCtx);
5744
  STailInfo*           pInfo = GET_ROWCELL_INTERBUF(pEntryInfo);
5745
  pEntryInfo->complete = true;
5746

5747
  int32_t type = pCtx->input.pData[0]->info.type;
5748
  int32_t slotId = pCtx->pExpr->base.resSchema.slotId;
5749

5750
  SColumnInfoData* pCol = taosArrayGet(pBlock->pDataBlock, slotId);
5751

5752
  // todo assign the tag value and the corresponding row data
5753
  int32_t currentRow = pBlock->info.rows;
5754
  for (int32_t i = 0; i < pEntryInfo->numOfRes; ++i) {
5755
    STailItem* pItem = pInfo->pItems[i];
5756
    colDataSetVal(pCol, currentRow, pItem->data, false);
5757
    currentRow += 1;
5758
  }
5759

5760
  return pEntryInfo->numOfRes;
5761
#endif
5762
  return 0;
×
5763
}
5764

5765
bool getUniqueFuncEnv(SFunctionNode* pFunc, SFuncExecEnv* pEnv) {
×
5766
#if 0
5767
  pEnv->calcMemSize = sizeof(SUniqueInfo) + UNIQUE_MAX_RESULT_SIZE;
5768
#endif
5769
  return true;
×
5770
}
5771

5772
int32_t uniqueFunctionSetup(SqlFunctionCtx* pCtx, SResultRowEntryInfo* pResInfo) {
×
5773
#if 0
5774
  if (!functionSetup(pCtx, pResInfo)) {
5775
    return false;
5776
  }
5777

5778
  SUniqueInfo* pInfo = GET_ROWCELL_INTERBUF(pResInfo);
5779
  pInfo->numOfPoints = 0;
5780
  pInfo->colType = pCtx->resDataInfo.type;
5781
  pInfo->colBytes = pCtx->resDataInfo.bytes;
5782
  if (pInfo->pHash != NULL) {
5783
    taosHashClear(pInfo->pHash);
5784
  } else {
5785
    pInfo->pHash = taosHashInit(64, taosGetDefaultHashFunction(TSDB_DATA_TYPE_BINARY), true, HASH_NO_LOCK);
5786
  }
5787
#endif
5788
  return TSDB_CODE_SUCCESS;
×
5789
}
5790

5791
#if 0
5792
static void doUniqueAdd(SUniqueInfo* pInfo, char* data, TSKEY ts, bool isNull) {
5793
  // handle null elements
5794
  if (isNull == true) {
5795
    int32_t      size = sizeof(SUniqueItem) + pInfo->colBytes;
5796
    SUniqueItem* pItem = (SUniqueItem*)(pInfo->pItems + pInfo->numOfPoints * size);
5797
    if (pInfo->hasNull == false && pItem->isNull == false) {
5798
      pItem->timestamp = ts;
5799
      pItem->isNull = true;
5800
      pInfo->numOfPoints++;
5801
      pInfo->hasNull = true;
5802
    } else if (pItem->timestamp > ts && pItem->isNull == true) {
5803
      pItem->timestamp = ts;
5804
    }
5805
    return;
5806
  }
5807

5808
  int32_t      hashKeyBytes = IS_VAR_DATA_TYPE(pInfo->colType) ? varDataTLen(data) : pInfo->colBytes;
5809
  SUniqueItem* pHashItem = taosHashGet(pInfo->pHash, data, hashKeyBytes);
5810
  if (pHashItem == NULL) {
5811
    int32_t      size = sizeof(SUniqueItem) + pInfo->colBytes;
5812
    SUniqueItem* pItem = (SUniqueItem*)(pInfo->pItems + pInfo->numOfPoints * size);
5813
    pItem->timestamp = ts;
5814
    memcpy(pItem->data, data, pInfo->colBytes);
5815

5816
    taosHashPut(pInfo->pHash, data, hashKeyBytes, (char*)pItem, sizeof(SUniqueItem*));
5817
    pInfo->numOfPoints++;
5818
  } else if (pHashItem->timestamp > ts) {
5819
    pHashItem->timestamp = ts;
5820
  }
5821
}
5822
#endif
5823

5824
int32_t uniqueFunction(SqlFunctionCtx* pCtx) {
×
5825
#if 0
5826
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
5827
  SUniqueInfo*         pInfo = GET_ROWCELL_INTERBUF(pResInfo);
5828

5829
  SInputColumnInfoData* pInput = &pCtx->input;
5830
  TSKEY*                tsList = (int64_t*)pInput->pPTS->pData;
5831

5832
  SColumnInfoData* pInputCol = pInput->pData[0];
5833
  SColumnInfoData* pTsOutput = pCtx->pTsOutput;
5834
  SColumnInfoData* pOutput = (SColumnInfoData*)pCtx->pOutput;
5835

5836
  int32_t startOffset = pCtx->offset;
5837
  for (int32_t i = pInput->startRowIndex; i < pInput->numOfRows + pInput->startRowIndex; ++i) {
5838
    char* data = colDataGetData(pInputCol, i);
5839
    doUniqueAdd(pInfo, data, tsList[i], colDataIsNull_s(pInputCol, i));
5840

5841
    if (sizeof(SUniqueInfo) + pInfo->numOfPoints * (sizeof(SUniqueItem) + pInfo->colBytes) >= UNIQUE_MAX_RESULT_SIZE) {
5842
      taosHashCleanup(pInfo->pHash);
5843
      return 0;
5844
    }
5845
  }
5846

5847
  for (int32_t i = 0; i < pInfo->numOfPoints; ++i) {
5848
    SUniqueItem* pItem = (SUniqueItem*)(pInfo->pItems + i * (sizeof(SUniqueItem) + pInfo->colBytes));
5849
    if (pItem->isNull == true) {
5850
      colDataSetNULL(pOutput, i);
5851
    } else {
5852
      colDataSetVal(pOutput, i, pItem->data, false);
5853
    }
5854
    if (pTsOutput != NULL) {
5855
      colDataSetInt64(pTsOutput, i, &pItem->timestamp);
5856
    }
5857
  }
5858

5859
  return pInfo->numOfPoints;
5860
#endif
5861
  return 0;
×
5862
}
5863

5864
bool getModeFuncEnv(SFunctionNode* pFunc, SFuncExecEnv* pEnv) {
24,942✔
5865
  pEnv->calcMemSize = sizeof(SModeInfo);
24,942✔
5866
  return true;
24,942✔
5867
}
5868

5869
int32_t modeFunctionSetup(SqlFunctionCtx* pCtx, SResultRowEntryInfo* pResInfo) {
21,796✔
5870
  if (pResInfo->initialized) {
21,796!
5871
    return TSDB_CODE_SUCCESS;
×
5872
  }
5873
  if (TSDB_CODE_SUCCESS != functionSetup(pCtx, pResInfo)) {
21,796!
5874
    return TSDB_CODE_FUNC_SETUP_ERROR;
×
5875
  }
5876

5877
  SModeInfo* pInfo = GET_ROWCELL_INTERBUF(pResInfo);
21,796✔
5878
  pInfo->colType = pCtx->resDataInfo.type;
21,796✔
5879
  pInfo->colBytes = pCtx->resDataInfo.bytes;
21,796✔
5880
  if (pInfo->pHash != NULL) {
21,796!
5881
    taosHashClear(pInfo->pHash);
×
5882
  } else {
5883
    pInfo->pHash = taosHashInit(64, taosGetDefaultHashFunction(TSDB_DATA_TYPE_BINARY), true, HASH_NO_LOCK);
21,796✔
5884
    if (NULL == pInfo->pHash) {
21,797!
5885
      return terrno;
×
5886
    }
5887
  }
5888
  pInfo->nullTupleSaved = false;
21,797✔
5889
  pInfo->nullTuplePos.pageId = -1;
21,797✔
5890

5891
  pInfo->buf = taosMemoryMalloc(pInfo->colBytes);
21,797!
5892
  if (NULL == pInfo->buf) {
21,797!
5893
    taosHashCleanup(pInfo->pHash);
×
5894
    pInfo->pHash = NULL;
×
5895
    return terrno;
×
5896
  }
5897
  pCtx->needCleanup = true;
21,797✔
5898
  return TSDB_CODE_SUCCESS;
21,797✔
5899
}
5900

5901
static void modeFunctionCleanup(SModeInfo* pInfo) {
21,797✔
5902
  taosHashCleanup(pInfo->pHash);
21,797✔
5903
  pInfo->pHash = NULL;
21,797✔
5904
  taosMemoryFreeClear(pInfo->buf);
21,797!
5905
}
21,797✔
5906

5907
void modeFunctionCleanupExt(SqlFunctionCtx* pCtx) {
×
5908
  if (pCtx == NULL || GET_RES_INFO(pCtx) == NULL || GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx)) == NULL) {
×
5909
    return;
×
5910
  }
5911
  modeFunctionCleanup(GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx)));
×
5912
}
5913

5914
static int32_t saveModeTupleData(SqlFunctionCtx* pCtx, char* data, SModeInfo* pInfo, STuplePos* pPos) {
48,662,995✔
5915
  if (IS_VAR_DATA_TYPE(pInfo->colType)) {
48,662,995!
5916
    if (pInfo->colType == TSDB_DATA_TYPE_JSON) {
9,993,280!
5917
      (void)memcpy(pInfo->buf, data, getJsonValueLen(data));
×
5918
    } else {
5919
      (void)memcpy(pInfo->buf, data, varDataTLen(data));
9,993,280✔
5920
    }
5921
  } else {
5922
    (void)memcpy(pInfo->buf, data, pInfo->colBytes);
38,669,715✔
5923
  }
5924

5925
  return doSaveTupleData(&pCtx->saveHandle, pInfo->buf, pInfo->colBytes, NULL, pPos, pCtx->pStore);
48,662,995✔
5926
}
5927

5928
static int32_t doModeAdd(SModeInfo* pInfo, int32_t rowIndex, SqlFunctionCtx* pCtx, char* data) {
49,664,992✔
5929
  int32_t code = TSDB_CODE_SUCCESS;
49,664,992✔
5930
  int32_t hashKeyBytes;
5931
  if (IS_VAR_DATA_TYPE(pInfo->colType)) {
49,664,992!
5932
    if (pInfo->colType == TSDB_DATA_TYPE_JSON) {
9,993,455!
5933
      hashKeyBytes = getJsonValueLen(data);
×
5934
    } else {
5935
      hashKeyBytes = varDataTLen(data);
9,993,455✔
5936
    }
5937
  } else {
5938
    hashKeyBytes = pInfo->colBytes;
39,671,537✔
5939
  }
5940

5941
  SModeItem* pHashItem = (SModeItem*)taosHashGet(pInfo->pHash, data, hashKeyBytes);
49,667,981✔
5942
  if (pHashItem == NULL) {
49,663,034✔
5943
    int32_t   size = sizeof(SModeItem);
48,662,388✔
5944
    SModeItem item = {0};
48,662,388✔
5945

5946
    item.count += 1;
48,662,388✔
5947
    code = saveModeTupleData(pCtx, data, pInfo, &item.dataPos);
48,662,388✔
5948
    if (code != TSDB_CODE_SUCCESS) {
48,660,661!
5949
      return code;
×
5950
    }
5951

5952
    if (pCtx->subsidiaries.num > 0) {
48,660,661✔
5953
      code = saveTupleData(pCtx, rowIndex, pCtx->pSrcBlock, &item.tuplePos);
28,035,755✔
5954
      if (code != TSDB_CODE_SUCCESS) {
28,035,755!
5955
        return code;
×
5956
      }
5957
    }
5958

5959
    code = taosHashPut(pInfo->pHash, data, hashKeyBytes, &item, sizeof(SModeItem));
48,660,661✔
5960
    if (code != TSDB_CODE_SUCCESS) {
48,666,729!
5961
      return code;
×
5962
    }
5963
  } else {
5964
    pHashItem->count += 1;
1,000,646✔
5965
    if (pCtx->subsidiaries.num > 0) {
1,000,646✔
5966
      code = updateTupleData(pCtx, rowIndex, pCtx->pSrcBlock, &pHashItem->tuplePos);
687,579✔
5967
      if (code != TSDB_CODE_SUCCESS) {
687,579!
5968
        return code;
×
5969
      }
5970
    }
5971
  }
5972

5973
  return code;
49,667,375✔
5974
}
5975

5976
int32_t modeFunction(SqlFunctionCtx* pCtx) {
216,482✔
5977
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
216,482✔
5978
  SModeInfo*           pInfo = GET_ROWCELL_INTERBUF(pResInfo);
216,482✔
5979

5980
  SInputColumnInfoData* pInput = &pCtx->input;
216,482✔
5981

5982
  SColumnInfoData* pInputCol = pInput->pData[0];
216,482✔
5983
  SColumnInfoData* pOutput = (SColumnInfoData*)pCtx->pOutput;
216,482✔
5984

5985
  int32_t numOfElems = 0;
216,482✔
5986
  int32_t startOffset = pCtx->offset;
216,482✔
5987
  for (int32_t i = pInput->startRowIndex; i < pInput->numOfRows + pInput->startRowIndex; ++i) {
50,297,426✔
5988
    if (colDataIsNull_s(pInputCol, i)) {
100,160,660✔
5989
      continue;
413,667✔
5990
    }
5991
    numOfElems++;
49,666,663✔
5992

5993
    char*   data = colDataGetData(pInputCol, i);
49,666,663!
5994
    int32_t code = doModeAdd(pInfo, i, pCtx, data);
49,666,663✔
5995
    if (code != TSDB_CODE_SUCCESS) {
49,667,334✔
5996
      modeFunctionCleanup(pInfo);
57✔
5997
      return code;
×
5998
    }
5999
  }
6000

6001
  if (numOfElems == 0 && pCtx->subsidiaries.num > 0 && !pInfo->nullTupleSaved) {
217,096!
6002
    int32_t code = saveTupleData(pCtx, pInput->startRowIndex, pCtx->pSrcBlock, &pInfo->nullTuplePos);
50✔
6003
    if (code != TSDB_CODE_SUCCESS) {
50!
6004
      modeFunctionCleanup(pInfo);
×
6005
      return code;
×
6006
    }
6007
    pInfo->nullTupleSaved = true;
50✔
6008
  }
6009

6010
  SET_VAL(pResInfo, numOfElems, 1);
217,096✔
6011

6012
  return TSDB_CODE_SUCCESS;
217,096✔
6013
}
6014

6015
int32_t modeFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
21,797✔
6016
  int32_t              code = TSDB_CODE_SUCCESS;
21,797✔
6017
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
21,797✔
6018
  SModeInfo*           pInfo = GET_ROWCELL_INTERBUF(pResInfo);
21,797✔
6019
  int32_t              slotId = pCtx->pExpr->base.resSchema.slotId;
21,797✔
6020
  SColumnInfoData*     pCol = taosArrayGet(pBlock->pDataBlock, slotId);
21,797✔
6021
  int32_t              currentRow = pBlock->info.rows;
21,797✔
6022
  if (NULL == pCol) {
21,797!
6023
    modeFunctionCleanup(pInfo);
×
6024
    return TSDB_CODE_OUT_OF_RANGE;
×
6025
  }
6026

6027
  STuplePos resDataPos, resTuplePos;
6028
  int32_t   maxCount = 0;
21,797✔
6029

6030
  void* pIter = taosHashIterate(pInfo->pHash, NULL);
21,797✔
6031
  while (pIter != NULL) {
48,689,477✔
6032
    SModeItem* pItem = (SModeItem*)pIter;
48,667,680✔
6033
    if (pItem->count >= maxCount) {
48,667,680✔
6034
      maxCount = pItem->count;
47,719,920✔
6035
      resDataPos = pItem->dataPos;
47,719,920✔
6036
      resTuplePos = pItem->tuplePos;
47,719,920✔
6037
    }
6038

6039
    pIter = taosHashIterate(pInfo->pHash, pIter);
48,667,680✔
6040
  }
6041

6042
  if (maxCount != 0) {
21,797✔
6043
    char* pData = NULL;
19,444✔
6044
    code = loadTupleData(pCtx, &resDataPos, &pData);
19,444✔
6045
    if (pData == NULL || TSDB_CODE_SUCCESS != code) {
19,444!
6046
      code = terrno = TSDB_CODE_NOT_FOUND;
×
6047
      qError("Load tuple data failed since %s, groupId:%" PRIu64 ", ts:%" PRId64, terrstr(),
×
6048
             resDataPos.streamTupleKey.groupId, resDataPos.streamTupleKey.ts);
6049
      modeFunctionCleanup(pInfo);
×
6050
      return code;
×
6051
    }
6052

6053
    code = colDataSetVal(pCol, currentRow, pData, false);
19,444✔
6054
    if (TSDB_CODE_SUCCESS != code) {
19,444!
6055
      modeFunctionCleanup(pInfo);
×
6056
      return code;
×
6057
    }
6058
    code = setSelectivityValue(pCtx, pBlock, &resTuplePos, currentRow);
19,444✔
6059
  } else {
6060
    colDataSetNULL(pCol, currentRow);
2,353✔
6061
    code = setSelectivityValue(pCtx, pBlock, &pInfo->nullTuplePos, currentRow);
2,353✔
6062
  }
6063

6064
  modeFunctionCleanup(pInfo);
21,797✔
6065

6066
  return code;
21,797✔
6067
}
6068

6069
bool getTwaFuncEnv(struct SFunctionNode* pFunc, SFuncExecEnv* pEnv) {
78,964✔
6070
  pEnv->calcMemSize = sizeof(STwaInfo);
78,964✔
6071
  return true;
78,964✔
6072
}
6073

6074
int32_t twaFunctionSetup(SqlFunctionCtx* pCtx, SResultRowEntryInfo* pResultInfo) {
10,759,266✔
6075
  if (pResultInfo->initialized) {
10,759,266!
6076
    return TSDB_CODE_SUCCESS;
×
6077
  }
6078
  if (TSDB_CODE_SUCCESS != functionSetup(pCtx, pResultInfo)) {
10,759,266!
6079
    return TSDB_CODE_FUNC_SETUP_ERROR;
×
6080
  }
6081

6082
  STwaInfo* pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
10,759,267✔
6083
  pInfo->numOfElems = 0;
10,759,267✔
6084
  pInfo->p.key = INT64_MIN;
10,759,267✔
6085
  pInfo->win = TSWINDOW_INITIALIZER;
10,759,267✔
6086
  return TSDB_CODE_SUCCESS;
10,759,267✔
6087
}
6088

6089
static double twa_get_area(SPoint1 s, SPoint1 e) {
29,338,361✔
6090
  if (e.key == INT64_MAX || s.key == INT64_MIN) {
29,338,361!
6091
    return 0;
×
6092
  }
6093

6094
  if ((s.val >= 0 && e.val >= 0) || (s.val <= 0 && e.val <= 0)) {
29,338,522✔
6095
    return (s.val + e.val) * (e.key - s.key) / 2;
17,535,248✔
6096
  }
6097

6098
  double x = (s.key * e.val - e.key * s.val) / (e.val - s.val);
11,803,274✔
6099
  double val = (s.val * (x - s.key) + e.val * (e.key - x)) / 2;
11,803,274✔
6100
  return val;
11,803,274✔
6101
}
6102

6103
int32_t twaFunction(SqlFunctionCtx* pCtx) {
10,765,403✔
6104
  int32_t               code = TSDB_CODE_SUCCESS;
10,765,403✔
6105
  SInputColumnInfoData* pInput = &pCtx->input;
10,765,403✔
6106
  SColumnInfoData*      pInputCol = pInput->pData[0];
10,765,403✔
6107

6108
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
10,765,403✔
6109
  STwaInfo*            pInfo = GET_ROWCELL_INTERBUF(pResInfo);
10,765,403✔
6110
  SPoint1*             last = &pInfo->p;
10,765,403✔
6111

6112
  if (IS_NULL_TYPE(pInputCol->info.type)) {
10,765,403!
6113
    pInfo->numOfElems = 0;
×
6114
    goto _twa_over;
×
6115
  }
6116

6117
  funcInputUpdate(pCtx);
10,765,403✔
6118
  SFuncInputRow row = {0};
10,765,485✔
6119
  bool          result = false;
10,765,485✔
6120
  if (pCtx->start.key != INT64_MIN && last->key == INT64_MIN) {
10,765,485!
6121
    while (1) {
6122
      code = funcInputGetNextRow(pCtx, &row, &result);
3,508,518✔
6123
      if (TSDB_CODE_SUCCESS != code) {
3,508,530!
6124
        return code;
×
6125
      }
6126
      if (!result) {
3,508,530✔
6127
        break;
2✔
6128
      }
6129
      if (row.isDataNull) {
3,508,528✔
6130
        continue;
2✔
6131
      }
6132

6133
      last->key = row.ts;
3,508,526✔
6134

6135
      GET_TYPED_DATA(last->val, double, pInputCol->info.type, row.pData);
3,508,526!
6136

6137
      pInfo->dOutput += twa_get_area(pCtx->start, *last);
3,508,526✔
6138
      pInfo->win.skey = pCtx->start.key;
3,508,522✔
6139
      pInfo->numOfElems++;
3,508,522✔
6140
      break;
3,508,522✔
6141
    }
6142
  } else if (pInfo->p.key == INT64_MIN) {
7,256,969✔
6143
    while (1) {
6144
      code = funcInputGetNextRow(pCtx, &row, &result);
7,372,171✔
6145
      if (TSDB_CODE_SUCCESS != code) {
7,371,813!
6146
        return code;
×
6147
      }
6148
      if (!result) {
7,371,813✔
6149
        break;
14,249✔
6150
      }
6151
      if (row.isDataNull) {
7,357,564✔
6152
        continue;
120,712✔
6153
      }
6154

6155
      last->key = row.ts;
7,236,852✔
6156

6157
      GET_TYPED_DATA(last->val, double, pInputCol->info.type, row.pData);
7,236,852!
6158

6159
      pInfo->win.skey = last->key;
7,236,852✔
6160
      pInfo->numOfElems++;
7,236,852✔
6161
      break;
7,236,852✔
6162
    }
6163
  }
6164

6165
  SPoint1 st = {0};
10,765,135✔
6166

6167
  // calculate the value of
6168
  while (1) {
6169
    code = funcInputGetNextRow(pCtx, &row, &result);
32,979,190✔
6170
    if (TSDB_CODE_SUCCESS != code) {
32,977,960!
6171
      return code;
×
6172
    }
6173
    if (!result) {
32,977,960✔
6174
      break;
10,765,297✔
6175
    }
6176
    if (row.isDataNull) {
22,212,663✔
6177
      continue;
630✔
6178
    }
6179
    pInfo->numOfElems++;
22,212,033✔
6180
    switch (pInputCol->info.type) {
22,212,033!
6181
      case TSDB_DATA_TYPE_TINYINT: {
908,020✔
6182
        INIT_INTP_POINT(st, row.ts, *(int8_t*)row.pData);
908,020✔
6183
        break;
908,020✔
6184
      }
6185
      case TSDB_DATA_TYPE_SMALLINT: {
2,551,529✔
6186
        INIT_INTP_POINT(st, row.ts, *(int16_t*)row.pData);
2,551,529✔
6187
        break;
2,551,529✔
6188
      }
6189
      case TSDB_DATA_TYPE_INT: {
120,585✔
6190
        INIT_INTP_POINT(st, row.ts, *(int32_t*)row.pData);
120,585✔
6191
        break;
120,585✔
6192
      }
6193
      case TSDB_DATA_TYPE_BIGINT: {
375,175✔
6194
        INIT_INTP_POINT(st, row.ts, *(int64_t*)row.pData);
375,175✔
6195
        break;
375,175✔
6196
      }
6197
      case TSDB_DATA_TYPE_FLOAT: {
17,904,256✔
6198
        INIT_INTP_POINT(st, row.ts, *(float_t*)row.pData);
17,904,256✔
6199
        break;
17,904,256✔
6200
      }
6201
      case TSDB_DATA_TYPE_DOUBLE: {
88,276✔
6202
        INIT_INTP_POINT(st, row.ts, *(double*)row.pData);
88,276✔
6203
        break;
88,276✔
6204
      }
6205
      case TSDB_DATA_TYPE_UTINYINT: {
68,007✔
6206
        INIT_INTP_POINT(st, row.ts, *(uint8_t*)row.pData);
68,007✔
6207
        break;
68,007✔
6208
      }
6209
      case TSDB_DATA_TYPE_USMALLINT: {
68,327✔
6210
        INIT_INTP_POINT(st, row.ts, *(uint16_t*)row.pData);
68,327✔
6211
        break;
68,327✔
6212
      }
6213
      case TSDB_DATA_TYPE_UINT: {
70,684✔
6214
        INIT_INTP_POINT(st, row.ts, *(uint32_t*)row.pData);
70,684✔
6215
        break;
70,684✔
6216
      }
6217
      case TSDB_DATA_TYPE_UBIGINT: {
58,673✔
6218
        INIT_INTP_POINT(st, row.ts, *(uint64_t*)row.pData);
58,673✔
6219
        break;
58,673✔
6220
      }
UNCOV
6221
      default: {
×
UNCOV
6222
        return TSDB_CODE_FUNC_FUNTION_PARA_TYPE;
×
6223
      }
6224
    }
6225
    if (pInfo->p.key == st.key) {
22,213,532!
6226
      return TSDB_CODE_FUNC_DUP_TIMESTAMP;
×
6227
    }
6228

6229
    pInfo->dOutput += twa_get_area(pInfo->p, st);
22,213,532✔
6230
    pInfo->p = st;
22,213,425✔
6231
  }
6232

6233
  // the last interpolated time window value
6234
  if (pCtx->end.key != INT64_MIN) {
10,765,297✔
6235
    pInfo->dOutput += twa_get_area(pInfo->p, pCtx->end);
3,617,273✔
6236
    pInfo->p = pCtx->end;
3,617,273✔
6237
    pInfo->numOfElems += 1;
3,617,273✔
6238
  }
6239

6240
  pInfo->win.ekey = pInfo->p.key;
10,765,297✔
6241

6242
_twa_over:
10,765,297✔
6243
  SET_VAL(pResInfo, 1, 1);
10,765,297✔
6244
  return TSDB_CODE_SUCCESS;
10,765,297✔
6245
}
6246

6247
/*
6248
 * To copy the input to interResBuf to avoid the input buffer space be over writen
6249
 * by next input data. The TWA function only applies to each table, so no merge procedure
6250
 * is required, we simply copy to the resut ot interResBuffer.
6251
 */
6252
// void twa_function_copy(SQLFunctionCtx *pCtx) {
6253
//   SResultRowEntryInfo *pResInfo = GET_RES_INFO(pCtx);
6254
//
6255
//   memcpy(GET_ROWCELL_INTERBUF(pResInfo), pCtx->pInput, (size_t)pCtx->inputBytes);
6256
//   pResInfo->hasResult = ((STwaInfo *)pCtx->pInput)->hasResult;
6257
// }
6258

6259
int32_t twaFinalize(struct SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
10,754,989✔
6260
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
10,754,989✔
6261

6262
  STwaInfo* pInfo = (STwaInfo*)GET_ROWCELL_INTERBUF(pResInfo);
10,754,989✔
6263
  if (pInfo->numOfElems == 0) {
10,754,989✔
6264
    pResInfo->numOfRes = 0;
14,069✔
6265
  } else {
6266
    if (pInfo->win.ekey == pInfo->win.skey) {
10,740,920✔
6267
      pInfo->dTwaRes = pInfo->p.val;
5,785,039✔
6268
    } else if (pInfo->win.ekey == INT64_MAX || pInfo->win.skey == INT64_MIN) {  // no data in timewindow
4,955,881!
UNCOV
6269
      pInfo->dTwaRes = 0;
×
6270
    } else {
6271
      pInfo->dTwaRes = pInfo->dOutput / (pInfo->win.ekey - pInfo->win.skey);
4,956,026✔
6272
    }
6273

6274
    pResInfo->numOfRes = 1;
10,740,920✔
6275
  }
6276

6277
  return functionFinalize(pCtx, pBlock);
10,754,989✔
6278
}
6279

6280
int32_t blockDistSetup(SqlFunctionCtx* pCtx, SResultRowEntryInfo* pResultInfo) {
1,628✔
6281
  if (pResultInfo->initialized) {
1,628!
6282
    return TSDB_CODE_SUCCESS;
×
6283
  }
6284
  if (TSDB_CODE_SUCCESS != functionSetup(pCtx, pResultInfo)) {
1,628!
6285
    return TSDB_CODE_FUNC_SETUP_ERROR;
×
6286
  }
6287

6288
  STableBlockDistInfo* pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
1,628✔
6289
  pInfo->minRows = INT32_MAX;
1,628✔
6290
  return TSDB_CODE_SUCCESS;
1,628✔
6291
}
6292

6293
int32_t blockDistFunction(SqlFunctionCtx* pCtx) {
3,253✔
6294
  const int32_t BLOCK_DIST_RESULT_ROWS = 25;
3,253✔
6295

6296
  SInputColumnInfoData* pInput = &pCtx->input;
3,253✔
6297
  SColumnInfoData*      pInputCol = pInput->pData[0];
3,253✔
6298
  SResultRowEntryInfo*  pResInfo = GET_RES_INFO(pCtx);
3,253✔
6299
  STableBlockDistInfo*  pDistInfo = GET_ROWCELL_INTERBUF(pResInfo);
3,253✔
6300

6301
  STableBlockDistInfo p1 = {0};
3,253✔
6302
  if (tDeserializeBlockDistInfo(varDataVal(pInputCol->pData), varDataLen(pInputCol->pData), &p1) < 0) {
3,253!
6303
    qError("failed to deserialize block dist info");
×
6304
    return TSDB_CODE_FAILED;
×
6305
  }
6306

6307
  pDistInfo->numOfBlocks += p1.numOfBlocks;
3,253✔
6308
  pDistInfo->numOfTables += p1.numOfTables;
3,253✔
6309
  pDistInfo->numOfInmemRows += p1.numOfInmemRows;
3,253✔
6310
  pDistInfo->numOfSttRows += p1.numOfSttRows;
3,253✔
6311
  pDistInfo->totalSize += p1.totalSize;
3,253✔
6312
  pDistInfo->totalRows += p1.totalRows;
3,253✔
6313
  pDistInfo->numOfFiles += p1.numOfFiles;
3,253✔
6314

6315
  pDistInfo->defMinRows = p1.defMinRows;
3,253✔
6316
  pDistInfo->defMaxRows = p1.defMaxRows;
3,253✔
6317
  pDistInfo->rowSize = p1.rowSize;
3,253✔
6318

6319
  if (pDistInfo->minRows > p1.minRows) {
3,253✔
6320
    pDistInfo->minRows = p1.minRows;
2✔
6321
  }
6322
  if (pDistInfo->maxRows < p1.maxRows) {
3,253✔
6323
    pDistInfo->maxRows = p1.maxRows;
2✔
6324
  }
6325
  pDistInfo->numOfVgroups += (p1.numOfTables != 0 ? 1 : 0);
3,253✔
6326
  for (int32_t i = 0; i < tListLen(pDistInfo->blockRowsHisto); ++i) {
68,313✔
6327
    pDistInfo->blockRowsHisto[i] += p1.blockRowsHisto[i];
65,060✔
6328
  }
6329

6330
  pResInfo->numOfRes = BLOCK_DIST_RESULT_ROWS;  // default output rows
3,253✔
6331
  return TSDB_CODE_SUCCESS;
3,253✔
6332
}
6333

6334
int32_t tSerializeBlockDistInfo(void* buf, int32_t bufLen, const STableBlockDistInfo* pInfo) {
6,488✔
6335
  SEncoder encoder = {0};
6,488✔
6336
  int32_t  code = 0;
6,488✔
6337
  int32_t  lino;
6338
  int32_t  tlen;
6339
  tEncoderInit(&encoder, buf, bufLen);
6,488✔
6340

6341
  TAOS_CHECK_EXIT(tStartEncode(&encoder));
6,496!
6342
  TAOS_CHECK_EXIT(tEncodeU32(&encoder, pInfo->rowSize));
12,978!
6343

6344
  TAOS_CHECK_EXIT(tEncodeU16(&encoder, pInfo->numOfFiles));
12,978!
6345
  TAOS_CHECK_EXIT(tEncodeU32(&encoder, pInfo->numOfBlocks));
12,978!
6346
  TAOS_CHECK_EXIT(tEncodeU32(&encoder, pInfo->numOfTables));
12,978!
6347

6348
  TAOS_CHECK_EXIT(tEncodeU64(&encoder, pInfo->totalSize));
12,978!
6349
  TAOS_CHECK_EXIT(tEncodeU64(&encoder, pInfo->totalRows));
12,978!
6350
  TAOS_CHECK_EXIT(tEncodeI32(&encoder, pInfo->maxRows));
12,978!
6351
  TAOS_CHECK_EXIT(tEncodeI32(&encoder, pInfo->minRows));
12,978!
6352
  TAOS_CHECK_EXIT(tEncodeI32(&encoder, pInfo->defMaxRows));
12,978!
6353
  TAOS_CHECK_EXIT(tEncodeI32(&encoder, pInfo->defMinRows));
12,978!
6354
  TAOS_CHECK_EXIT(tEncodeU32(&encoder, pInfo->numOfInmemRows));
12,978!
6355
  TAOS_CHECK_EXIT(tEncodeU32(&encoder, pInfo->numOfSttRows));
12,978!
6356
  TAOS_CHECK_EXIT(tEncodeU32(&encoder, pInfo->numOfVgroups));
12,978!
6357

6358
  for (int32_t i = 0; i < tListLen(pInfo->blockRowsHisto); ++i) {
136,286✔
6359
    TAOS_CHECK_EXIT(tEncodeI32(&encoder, pInfo->blockRowsHisto[i]));
259,594!
6360
  }
6361

6362
  tEndEncode(&encoder);
6,489✔
6363

6364
_exit:
6,497✔
6365
  if (code) {
6,497!
6366
    tlen = code;
×
6367
  } else {
6368
    tlen = encoder.pos;
6,497✔
6369
  }
6370
  tEncoderClear(&encoder);
6,497✔
6371
  return tlen;
6,490✔
6372
}
6373

6374
int32_t tDeserializeBlockDistInfo(void* buf, int32_t bufLen, STableBlockDistInfo* pInfo) {
3,253✔
6375
  SDecoder decoder = {0};
3,253✔
6376
  int32_t  code = 0;
3,253✔
6377
  int32_t  lino;
6378
  tDecoderInit(&decoder, buf, bufLen);
3,253✔
6379

6380
  TAOS_CHECK_EXIT(tStartDecode(&decoder));
3,253!
6381
  TAOS_CHECK_EXIT(tDecodeU32(&decoder, &pInfo->rowSize));
6,506!
6382

6383
  TAOS_CHECK_EXIT(tDecodeU16(&decoder, &pInfo->numOfFiles));
6,506!
6384
  TAOS_CHECK_EXIT(tDecodeU32(&decoder, &pInfo->numOfBlocks));
6,506!
6385
  TAOS_CHECK_EXIT(tDecodeU32(&decoder, &pInfo->numOfTables));
6,506!
6386

6387
  TAOS_CHECK_EXIT(tDecodeU64(&decoder, &pInfo->totalSize));
6,506!
6388
  TAOS_CHECK_EXIT(tDecodeU64(&decoder, &pInfo->totalRows));
6,506!
6389
  TAOS_CHECK_EXIT(tDecodeI32(&decoder, &pInfo->maxRows));
6,506!
6390
  TAOS_CHECK_EXIT(tDecodeI32(&decoder, &pInfo->minRows));
6,506!
6391
  TAOS_CHECK_EXIT(tDecodeI32(&decoder, &pInfo->defMaxRows));
6,506!
6392
  TAOS_CHECK_EXIT(tDecodeI32(&decoder, &pInfo->defMinRows));
6,506!
6393
  TAOS_CHECK_EXIT(tDecodeU32(&decoder, &pInfo->numOfInmemRows));
6,506!
6394
  TAOS_CHECK_EXIT(tDecodeU32(&decoder, &pInfo->numOfSttRows));
6,506!
6395
  TAOS_CHECK_EXIT(tDecodeU32(&decoder, &pInfo->numOfVgroups));
6,506!
6396

6397
  for (int32_t i = 0; i < tListLen(pInfo->blockRowsHisto); ++i) {
68,313✔
6398
    TAOS_CHECK_EXIT(tDecodeI32(&decoder, &pInfo->blockRowsHisto[i]));
130,120!
6399
  }
6400

6401
_exit:
3,253✔
6402
  tDecoderClear(&decoder);
3,253✔
6403
  return code;
3,253✔
6404
}
6405

6406
int32_t blockDistFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
1,628✔
6407
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
1,628✔
6408
  STableBlockDistInfo* pData = GET_ROWCELL_INTERBUF(pResInfo);
1,628✔
6409

6410
  SColumnInfoData* pColInfo = taosArrayGet(pBlock->pDataBlock, 0);
1,628✔
6411
  if (NULL == pColInfo) {
1,628!
6412
    return TSDB_CODE_OUT_OF_RANGE;
×
6413
  }
6414

6415
  if (pData->totalRows == 0) {
1,628✔
6416
    pData->minRows = 0;
1,626✔
6417
  }
6418

6419
  int32_t row = 0;
1,628✔
6420
  char    st[256] = {0};
1,628✔
6421
  double  averageSize = 0;
1,628✔
6422
  if (pData->numOfBlocks != 0) {
1,628✔
6423
    averageSize = ((double)pData->totalSize) / pData->numOfBlocks;
2✔
6424
  }
6425
  uint64_t totalRawSize = pData->totalRows * pData->rowSize;
1,628✔
6426
  double   compRatio = 0;
1,628✔
6427
  if (totalRawSize != 0) {
1,628✔
6428
    compRatio = pData->totalSize * 100 / (double)totalRawSize;
2✔
6429
  }
6430

6431
  int32_t len = tsnprintf(varDataVal(st), sizeof(st) - VARSTR_HEADER_SIZE,
3,256✔
6432
                          "Total_Blocks=[%d] Total_Size=[%.2f KiB] Average_size=[%.2f KiB] Compression_Ratio=[%.2f %c]",
6433
                          pData->numOfBlocks, pData->totalSize / 1024.0, averageSize / 1024.0, compRatio, '%');
1,628✔
6434

6435
  varDataSetLen(st, len);
1,628✔
6436
  int32_t code = colDataSetVal(pColInfo, row++, st, false);
1,628✔
6437
  if (TSDB_CODE_SUCCESS != code) {
1,628!
6438
    return code;
×
6439
  }
6440

6441
  int64_t avgRows = 0;
1,628✔
6442
  if (pData->numOfBlocks > 0) {
1,628✔
6443
    avgRows = pData->totalRows / pData->numOfBlocks;
2✔
6444
  }
6445

6446
  len = tsnprintf(varDataVal(st), sizeof(st) - VARSTR_HEADER_SIZE,
1,628✔
6447
                  "Block_Rows=[%" PRId64 "] MinRows=[%d] MaxRows=[%d] AvgRows=[%" PRId64 "]", pData->totalRows,
6448
                  pData->minRows, pData->maxRows, avgRows);
6449
  varDataSetLen(st, len);
1,628✔
6450
  code = colDataSetVal(pColInfo, row++, st, false);
1,628✔
6451
  if (TSDB_CODE_SUCCESS != code) {
1,628!
6452
    return code;
×
6453
  }
6454

6455
  len = tsnprintf(varDataVal(st), sizeof(st) - VARSTR_HEADER_SIZE, "Inmem_Rows=[%u] Stt_Rows=[%u] ",
1,628✔
6456
                  pData->numOfInmemRows, pData->numOfSttRows);
6457
  varDataSetLen(st, len);
1,628✔
6458
  code = colDataSetVal(pColInfo, row++, st, false);
1,628✔
6459
  if (TSDB_CODE_SUCCESS != code) {
1,628!
6460
    return code;
×
6461
  }
6462

6463
  len = tsnprintf(varDataVal(st), sizeof(st) - VARSTR_HEADER_SIZE,
3,256✔
6464
                  "Total_Tables=[%d] Total_Filesets=[%d] Total_Vgroups=[%d]", pData->numOfTables, pData->numOfFiles,
1,628✔
6465
                  pData->numOfVgroups);
6466

6467
  varDataSetLen(st, len);
1,628✔
6468
  code = colDataSetVal(pColInfo, row++, st, false);
1,628✔
6469
  if (TSDB_CODE_SUCCESS != code) {
1,628!
6470
    return code;
×
6471
  }
6472

6473
  len = tsnprintf(varDataVal(st), sizeof(st) - VARSTR_HEADER_SIZE,
1,628✔
6474
                  "--------------------------------------------------------------------------------");
6475
  varDataSetLen(st, len);
1,628✔
6476
  code = colDataSetVal(pColInfo, row++, st, false);
1,628✔
6477
  if (TSDB_CODE_SUCCESS != code) {
1,628!
6478
    return code;
×
6479
  }
6480

6481
  int32_t maxVal = 0;
1,628✔
6482
  int32_t minVal = INT32_MAX;
1,628✔
6483
  for (int32_t i = 0; i < tListLen(pData->blockRowsHisto); ++i) {
34,188✔
6484
    if (maxVal < pData->blockRowsHisto[i]) {
32,560✔
6485
      maxVal = pData->blockRowsHisto[i];
4✔
6486
    }
6487

6488
    if (minVal > pData->blockRowsHisto[i]) {
32,560✔
6489
      minVal = pData->blockRowsHisto[i];
1,629✔
6490
    }
6491
  }
6492

6493
  // maximum number of step is 80
6494
  double factor = pData->numOfBlocks / 80.0;
1,628✔
6495

6496
  int32_t numOfBuckets = sizeof(pData->blockRowsHisto) / sizeof(pData->blockRowsHisto[0]);
1,628✔
6497
  int32_t bucketRange = ceil(((double)(pData->defMaxRows - pData->defMinRows)) / numOfBuckets);
1,628✔
6498

6499
  for (int32_t i = 0; i < tListLen(pData->blockRowsHisto); ++i) {
34,188✔
6500
    len =
32,560✔
6501
        tsnprintf(varDataVal(st), sizeof(st) - VARSTR_HEADER_SIZE, "%04d |", pData->defMinRows + bucketRange * (i + 1));
32,560✔
6502

6503
    int32_t num = 0;
32,560✔
6504
    if (pData->blockRowsHisto[i] > 0) {
32,560✔
6505
      num = (pData->blockRowsHisto[i]) / factor;
4✔
6506
    }
6507

6508
    for (int32_t j = 0; j < num; ++j) {
32,719✔
6509
      int32_t x = tsnprintf(varDataVal(st) + len, sizeof(st) - VARSTR_HEADER_SIZE - len, "%c", '|');
159✔
6510
      len += x;
159✔
6511
    }
6512

6513
    if (pData->blockRowsHisto[i] > 0) {
32,560✔
6514
      double v = pData->blockRowsHisto[i] * 100.0 / pData->numOfBlocks;
4✔
6515
      len += tsnprintf(varDataVal(st) + len, sizeof(st) - VARSTR_HEADER_SIZE - len, "  %d (%.2f%c)",
4✔
6516
                       pData->blockRowsHisto[i], v, '%');
6517
    }
6518

6519
    varDataSetLen(st, len);
32,560✔
6520
    code = colDataSetVal(pColInfo, row++, st, false);
32,560✔
6521
    if (TSDB_CODE_SUCCESS != code) {
32,560!
6522
      return code;
×
6523
    }
6524
  }
6525

6526
  return TSDB_CODE_SUCCESS;
1,628✔
6527
}
6528
int32_t blockDBUsageSetup(SqlFunctionCtx* pCtx, SResultRowEntryInfo* pResultInfo) {
1✔
6529
  if (pResultInfo->initialized) {
1!
6530
    return TSDB_CODE_SUCCESS;
×
6531
  }
6532
  if (TSDB_CODE_SUCCESS != functionSetup(pCtx, pResultInfo)) {
1!
6533
    return TSDB_CODE_FUNC_SETUP_ERROR;
×
6534
  }
6535

6536
  SDBBlockUsageInfo* pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
1✔
6537
  return TSDB_CODE_SUCCESS;
1✔
6538
}
6539
int32_t blockDBUsageFunction(SqlFunctionCtx* pCtx) {
2✔
6540
  const int32_t BLOCK_DISK_USAGE_RESULT_ROWS = 2;
2✔
6541

6542
  SInputColumnInfoData* pInput = &pCtx->input;
2✔
6543
  SColumnInfoData*      pInputCol = pInput->pData[0];
2✔
6544
  SResultRowEntryInfo*  pResInfo = GET_RES_INFO(pCtx);
2✔
6545
  SDBBlockUsageInfo*    pDistInfo = GET_ROWCELL_INTERBUF(pResInfo);
2✔
6546

6547
  SDBBlockUsageInfo p1 = {0};
2✔
6548
  if (tDeserializeBlockDbUsage(varDataVal(pInputCol->pData), varDataLen(pInputCol->pData), &p1) < 0) {
2!
6549
    qError("failed to deserialize block dist info");
×
6550
    return TSDB_CODE_FAILED;
×
6551
  }
6552

6553
  pDistInfo->dataInDiskSize += p1.dataInDiskSize;
2✔
6554
  pDistInfo->walInDiskSize += p1.walInDiskSize;
2✔
6555
  pDistInfo->rawDataSize += p1.rawDataSize;
2✔
6556
  pResInfo->numOfRes = BLOCK_DISK_USAGE_RESULT_ROWS;  // default output rows
2✔
6557
  return TSDB_CODE_SUCCESS;
2✔
6558
}
6559

6560
int32_t tSerializeBlockDbUsage(void* buf, int32_t bufLen, const SDBBlockUsageInfo* pInfo) {
4✔
6561
  SEncoder encoder = {0};
4✔
6562
  int32_t  code = 0;
4✔
6563
  int32_t  lino;
6564
  int32_t  tlen;
6565
  tEncoderInit(&encoder, buf, bufLen);
4✔
6566

6567
  TAOS_CHECK_EXIT(tStartEncode(&encoder));
4!
6568

6569
  TAOS_CHECK_EXIT(tEncodeU64(&encoder, pInfo->dataInDiskSize));
8!
6570
  TAOS_CHECK_EXIT(tEncodeU64(&encoder, pInfo->walInDiskSize));
8!
6571
  TAOS_CHECK_EXIT(tEncodeU64(&encoder, pInfo->rawDataSize));
8!
6572

6573
  tEndEncode(&encoder);
4✔
6574

6575
_exit:
4✔
6576
  if (code) {
4!
6577
    tlen = code;
×
6578
  } else {
6579
    tlen = encoder.pos;
4✔
6580
  }
6581
  tEncoderClear(&encoder);
4✔
6582
  return tlen;
4✔
6583
}
6584
int32_t tDeserializeBlockDbUsage(void* buf, int32_t bufLen, SDBBlockUsageInfo* pInfo) {
2✔
6585
  SDecoder decoder = {0};
2✔
6586
  int32_t  code = 0;
2✔
6587
  int32_t  lino;
6588
  tDecoderInit(&decoder, buf, bufLen);
2✔
6589

6590
  TAOS_CHECK_EXIT(tStartDecode(&decoder));
2!
6591
  TAOS_CHECK_EXIT(tDecodeU64(&decoder, &pInfo->dataInDiskSize));
4!
6592
  TAOS_CHECK_EXIT(tDecodeU64(&decoder, &pInfo->walInDiskSize));
4!
6593
  TAOS_CHECK_EXIT(tDecodeU64(&decoder, &pInfo->rawDataSize));
4!
6594

6595
_exit:
2✔
6596
  tDecoderClear(&decoder);
2✔
6597
  return code;
2✔
6598
}
6599
int32_t blockDBUsageFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
1✔
6600
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
1✔
6601
  SDBBlockUsageInfo*   pData = GET_ROWCELL_INTERBUF(pResInfo);
1✔
6602

6603
  SColumnInfoData* pColInfo = taosArrayGet(pBlock->pDataBlock, 0);
1✔
6604
  if (NULL == pColInfo) {
1!
6605
    return TSDB_CODE_OUT_OF_RANGE;
×
6606
  }
6607
  int32_t len = 0;
1✔
6608
  int32_t row = 0;
1✔
6609
  char    st[256] = {0};
1✔
6610

6611
  uint64_t totalDiskSize = pData->dataInDiskSize;
1✔
6612
  uint64_t rawDataSize = pData->rawDataSize;
1✔
6613
  double   compressRatio = 0;
1✔
6614
  if (rawDataSize != 0) {
1!
6615
    compressRatio = totalDiskSize * 100 / (double)rawDataSize;
1✔
6616
    len = tsnprintf(varDataVal(st), sizeof(st) - VARSTR_HEADER_SIZE, "Compress_ratio=[%.2f%]", compressRatio);
1✔
6617
  } else {
6618
    len = tsnprintf(varDataVal(st), sizeof(st) - VARSTR_HEADER_SIZE, "Compress_ratio=[NULL]");
×
6619
  }
6620

6621
  varDataSetLen(st, len);
1✔
6622
  int32_t code = colDataSetVal(pColInfo, row++, st, false);
1✔
6623
  if (TSDB_CODE_SUCCESS != code) {
1!
6624
    return code;
×
6625
  }
6626

6627
  len =
1✔
6628
      tsnprintf(varDataVal(st), sizeof(st) - VARSTR_HEADER_SIZE, "Disk_occupied=[%" PRId64 "k]", pData->dataInDiskSize);
1✔
6629
  varDataSetLen(st, len);
1✔
6630
  code = colDataSetVal(pColInfo, row++, st, false);
1✔
6631
  if (TSDB_CODE_SUCCESS != code) {
1!
6632
    return code;
×
6633
  }
6634
  return code;
1✔
6635
}
6636

6637
bool getDerivativeFuncEnv(struct SFunctionNode* pFunc, SFuncExecEnv* pEnv) {
30,638✔
6638
  pEnv->calcMemSize = sizeof(SDerivInfo);
30,638✔
6639
  return true;
30,638✔
6640
}
6641

6642
int32_t derivativeFuncSetup(SqlFunctionCtx* pCtx, SResultRowEntryInfo* pResInfo) {
61,406✔
6643
  if (pResInfo->initialized) {
61,406✔
6644
    return TSDB_CODE_SUCCESS;
30,638✔
6645
  }
6646
  if (TSDB_CODE_SUCCESS != functionSetup(pCtx, pResInfo)) {
30,768!
6647
    return TSDB_CODE_FUNC_SETUP_ERROR;
×
6648
  }
6649

6650
  SDerivInfo* pDerivInfo = GET_ROWCELL_INTERBUF(pResInfo);
30,768✔
6651

6652
  pDerivInfo->ignoreNegative = pCtx->param[2].param.i;
30,768✔
6653
  pDerivInfo->prevTs = -1;
30,768✔
6654
  pDerivInfo->tsWindow = pCtx->param[1].param.i;
30,768✔
6655
  pDerivInfo->valueSet = false;
30,768✔
6656
  return TSDB_CODE_SUCCESS;
30,768✔
6657
}
6658

6659
int32_t derivativeFunction(SqlFunctionCtx* pCtx) {
30,768✔
6660
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
30,768✔
6661
  SDerivInfo*          pDerivInfo = GET_ROWCELL_INTERBUF(pResInfo);
30,768✔
6662

6663
  SInputColumnInfoData* pInput = &pCtx->input;
30,768✔
6664
  SColumnInfoData*      pInputCol = pInput->pData[0];
30,768✔
6665

6666
  int32_t          numOfElems = 0;
30,768✔
6667
  SColumnInfoData* pOutput = (SColumnInfoData*)pCtx->pOutput;
30,768✔
6668
  SColumnInfoData* pTsOutput = pCtx->pTsOutput;
30,768✔
6669
  int32_t          code = TSDB_CODE_SUCCESS;
30,768✔
6670

6671
  funcInputUpdate(pCtx);
30,768✔
6672

6673
  double v = 0;
30,768✔
6674
  if (pCtx->order == TSDB_ORDER_ASC) {
30,768✔
6675
    SFuncInputRow row = {0};
27,377✔
6676
    bool          result = false;
27,377✔
6677
    while (1) {
3,519,299✔
6678
      code = funcInputGetNextRow(pCtx, &row, &result);
3,546,676✔
6679
      if (TSDB_CODE_SUCCESS != code) {
3,546,676!
6680
        return code;
×
6681
      }
6682
      if (!result) {
3,546,676✔
6683
        break;
27,377✔
6684
      }
6685
      if (row.isDataNull) {
3,519,299✔
6686
        continue;
37,060✔
6687
      }
6688

6689
      char* d = row.pData;
3,482,239✔
6690
      GET_TYPED_DATA(v, double, pInputCol->info.type, d);
3,482,239!
6691

6692
      int32_t pos = pCtx->offset + numOfElems;
3,482,239✔
6693
      if (!pDerivInfo->valueSet) {  // initial value is not set yet
3,482,239✔
6694
        pDerivInfo->valueSet = true;
27,005✔
6695
      } else {
6696
        if (row.ts == pDerivInfo->prevTs) {
3,455,234!
6697
          return TSDB_CODE_FUNC_DUP_TIMESTAMP;
×
6698
        }
6699
        double r = ((v - pDerivInfo->prevValue) * pDerivInfo->tsWindow) / (row.ts - pDerivInfo->prevTs);
3,455,234✔
6700
        if (pDerivInfo->ignoreNegative && r < 0) {
3,455,234✔
6701
        } else {
6702
          if (isinf(r) || isnan(r)) {
2,119,391!
6703
            colDataSetNULL(pOutput, pos);
×
6704
          } else {
6705
            code = colDataSetVal(pOutput, pos, (const char*)&r, false);
2,119,391✔
6706
            if (code != TSDB_CODE_SUCCESS) {
2,119,391!
6707
              return code;
×
6708
            }
6709
          }
6710

6711
          if (pTsOutput != NULL) {
2,119,391!
6712
            colDataSetInt64(pTsOutput, pos, &row.ts);
×
6713
          }
6714

6715
          // handle selectivity
6716
          if (pCtx->subsidiaries.num > 0) {
2,119,391✔
6717
            code = appendSelectivityCols(pCtx, row.block, row.rowIndex, pos);
1,625,385✔
6718
            if (code != TSDB_CODE_SUCCESS) {
1,625,385!
6719
              return code;
×
6720
            }
6721
          }
6722

6723
          numOfElems++;
2,119,391✔
6724
        }
6725
      }
6726

6727
      pDerivInfo->prevValue = v;
3,482,239✔
6728
      pDerivInfo->prevTs = row.ts;
3,482,239✔
6729
    }
6730
  } else {
6731
    SFuncInputRow row = {0};
3,391✔
6732
    bool          result = false;
3,391✔
6733
    while (1) {
335,137✔
6734
      code = funcInputGetNextRow(pCtx, &row, &result);
338,528✔
6735
      if (TSDB_CODE_SUCCESS != code) {
338,528!
6736
        return code;
×
6737
      }
6738
      if (!result) {
338,528✔
6739
        break;
3,391✔
6740
      }
6741
      if (row.isDataNull) {
335,137✔
6742
        continue;
441✔
6743
      }
6744

6745
      char* d = row.pData;
334,696✔
6746
      GET_TYPED_DATA(v, double, pInputCol->info.type, d);
334,696!
6747

6748
      int32_t pos = pCtx->offset + numOfElems;
334,696✔
6749
      if (!pDerivInfo->valueSet) {  // initial value is not set yet
334,696✔
6750
        pDerivInfo->valueSet = true;
3,367✔
6751
      } else {
6752
        if (row.ts == pDerivInfo->prevTs) {
331,329!
6753
          return TSDB_CODE_FUNC_DUP_TIMESTAMP;
×
6754
        }
6755
        double r = ((pDerivInfo->prevValue - v) * pDerivInfo->tsWindow) / (pDerivInfo->prevTs - row.ts);
331,329✔
6756
        if (pDerivInfo->ignoreNegative && r < 0) {
331,329✔
6757
        } else {
6758
          if (isinf(r) || isnan(r)) {
170,685!
6759
            colDataSetNULL(pOutput, pos);
×
6760
          } else {
6761
            code = colDataSetVal(pOutput, pos, (const char*)&r, false);
170,685✔
6762
            if (code != TSDB_CODE_SUCCESS) {
170,685!
6763
              return code;
×
6764
            }
6765
          }
6766

6767
          if (pTsOutput != NULL) {
170,685!
6768
            colDataSetInt64(pTsOutput, pos, &pDerivInfo->prevTs);
×
6769
          }
6770

6771
          // handle selectivity
6772
          if (pCtx->subsidiaries.num > 0) {
170,685✔
6773
            code = appendSelectivityCols(pCtx, row.block, row.rowIndex, pos);
58,752✔
6774
            if (code != TSDB_CODE_SUCCESS) {
58,752!
6775
              return code;
×
6776
            }
6777
          }
6778
          numOfElems++;
170,685✔
6779
        }
6780
      }
6781

6782
      pDerivInfo->prevValue = v;
334,696✔
6783
      pDerivInfo->prevTs = row.ts;
334,696✔
6784
    }
6785
  }
6786

6787
  pResInfo->numOfRes = numOfElems;
30,768✔
6788

6789
  return TSDB_CODE_SUCCESS;
30,768✔
6790
}
6791

6792
int32_t getIrateInfoSize(int32_t pkBytes) { return (int32_t)sizeof(SRateInfo) + 2 * pkBytes; }
2,481,543✔
6793

6794
bool getIrateFuncEnv(struct SFunctionNode* pFunc, SFuncExecEnv* pEnv) {
123,886✔
6795
  int32_t pkBytes = (pFunc->hasPk) ? pFunc->pkBytes : 0;
123,886✔
6796
  pEnv->calcMemSize = getIrateInfoSize(pkBytes);
123,886✔
6797
  return true;
124,080✔
6798
}
6799

6800
int32_t irateFuncSetup(SqlFunctionCtx* pCtx, SResultRowEntryInfo* pResInfo) {
10,118,211✔
6801
  if (pResInfo->initialized) {
10,118,211!
6802
    return TSDB_CODE_SUCCESS;
×
6803
  }
6804
  if (TSDB_CODE_SUCCESS != functionSetup(pCtx, pResInfo)) {
10,118,211!
6805
    return TSDB_CODE_FUNC_SETUP_ERROR;
×
6806
  }
6807

6808
  SRateInfo* pInfo = GET_ROWCELL_INTERBUF(pResInfo);
10,118,226✔
6809

6810
  pInfo->firstKey = INT64_MIN;
10,118,226✔
6811
  pInfo->lastKey = INT64_MIN;
10,118,226✔
6812
  pInfo->firstValue = (double)INT64_MIN;
10,118,226✔
6813
  pInfo->lastValue = (double)INT64_MIN;
10,118,226✔
6814

6815
  pInfo->hasResult = 0;
10,118,226✔
6816
  return TSDB_CODE_SUCCESS;
10,118,226✔
6817
}
6818

6819
static void doSaveRateInfo(SRateInfo* pRateInfo, bool isFirst, int64_t ts, char* pk, double v) {
30,671,079✔
6820
  if (isFirst) {
30,671,079✔
6821
    pRateInfo->firstValue = v;
11,460,630✔
6822
    pRateInfo->firstKey = ts;
11,460,630✔
6823
    if (pRateInfo->firstPk) {
11,460,630✔
6824
      int32_t pkBytes;
6825
      if (IS_VAR_DATA_TYPE(pRateInfo->pkType)) {
35!
6826
        if (pRateInfo->pkType == TSDB_DATA_TYPE_JSON) {
8!
6827
          pkBytes = getJsonValueLen(pk);
×
6828
        } else {
6829
          pkBytes = varDataTLen(pk);
8✔
6830
        }
6831
      } else {
6832
        pkBytes = pRateInfo->pkBytes;
27✔
6833
      }
6834
      (void)memcpy(pRateInfo->firstPk, pk, pkBytes);
35✔
6835
    }
6836
  } else {
6837
    pRateInfo->lastValue = v;
19,210,449✔
6838
    pRateInfo->lastKey = ts;
19,210,449✔
6839
    if (pRateInfo->lastPk) {
19,210,449✔
6840
      int32_t pkBytes;
6841
      if (IS_VAR_DATA_TYPE(pRateInfo->pkType)) {
52!
6842
        if (pRateInfo->pkType == TSDB_DATA_TYPE_JSON) {
12!
6843
          pkBytes = getJsonValueLen(pk);
×
6844
        } else {
6845
          pkBytes = varDataTLen(pk);
12✔
6846
        }
6847
      } else {
6848
        pkBytes = pRateInfo->pkBytes;
40✔
6849
      }
6850
      (void)memcpy(pRateInfo->lastPk, pk, pkBytes);
52✔
6851
    }
6852
  }
6853
}
30,671,079✔
6854

6855
static void initializeRateInfo(SqlFunctionCtx* pCtx, SRateInfo* pRateInfo, bool isMerge) {
12,490,500✔
6856
  if (pCtx->hasPrimaryKey) {
12,490,500✔
6857
    if (!isMerge) {
19✔
6858
      pRateInfo->pkType = pCtx->input.pPrimaryKey->info.type;
17✔
6859
      pRateInfo->pkBytes = pCtx->input.pPrimaryKey->info.bytes;
17✔
6860
      pRateInfo->firstPk = pRateInfo->pkData;
17✔
6861
      pRateInfo->lastPk = pRateInfo->pkData + pRateInfo->pkBytes;
17✔
6862
    } else {
6863
      pRateInfo->firstPk = pRateInfo->pkData;
2✔
6864
      pRateInfo->lastPk = pRateInfo->pkData + pRateInfo->pkBytes;
2✔
6865
    }
6866
  } else {
6867
    pRateInfo->firstPk = NULL;
12,490,481✔
6868
    pRateInfo->lastPk = NULL;
12,490,481✔
6869
  }
6870
}
12,490,500✔
6871

6872
int32_t irateFunction(SqlFunctionCtx* pCtx) {
7,778,932✔
6873
  int32_t              code = TSDB_CODE_SUCCESS;
7,778,932✔
6874
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
7,778,932✔
6875
  SRateInfo*           pRateInfo = GET_ROWCELL_INTERBUF(pResInfo);
7,778,932✔
6876

6877
  SInputColumnInfoData* pInput = &pCtx->input;
7,778,932✔
6878
  SColumnInfoData*      pInputCol = pInput->pData[0];
7,778,932✔
6879

6880
  SColumnInfoData* pOutput = (SColumnInfoData*)pCtx->pOutput;
7,778,932✔
6881

6882
  funcInputUpdate(pCtx);
7,778,932✔
6883

6884
  initializeRateInfo(pCtx, pRateInfo, false);
7,778,976✔
6885

6886
  int32_t       numOfElems = 0;
7,778,962✔
6887
  int32_t       type = pInputCol->info.type;
7,778,962✔
6888
  SFuncInputRow row = {0};
7,778,962✔
6889
  bool          result = false;
7,778,962✔
6890
  while (1) {
17,394,595✔
6891
    code = funcInputGetNextRow(pCtx, &row, &result);
25,173,557✔
6892
    if (TSDB_CODE_SUCCESS != code) {
25,172,449!
6893
      return code;
×
6894
    }
6895
    if (!result) {
25,172,449✔
6896
      break;
7,778,845✔
6897
    }
6898
    if (row.isDataNull) {
17,393,604✔
6899
      continue;
120,608✔
6900
    }
6901

6902
    char*  data = row.pData;
17,272,996✔
6903
    double v = 0;
17,272,996✔
6904
    GET_TYPED_DATA(v, double, type, data);
17,272,996!
6905

6906
    if (INT64_MIN == pRateInfo->lastKey) {
17,272,996✔
6907
      doSaveRateInfo(pRateInfo, false, row.ts, row.pPk, v);
7,751,130✔
6908
      pRateInfo->hasResult = 1;
7,751,124✔
6909
      continue;
7,751,124✔
6910
    }
6911

6912
    if (row.ts > pRateInfo->lastKey) {
9,521,866✔
6913
      if ((INT64_MIN == pRateInfo->firstKey) || pRateInfo->lastKey > pRateInfo->firstKey) {
9,104,342!
6914
        doSaveRateInfo(pRateInfo, true, pRateInfo->lastKey, pRateInfo->lastPk, pRateInfo->lastValue);
9,104,345✔
6915
      }
6916
      doSaveRateInfo(pRateInfo, false, row.ts, row.pPk, v);
9,104,330✔
6917
      continue;
9,104,321✔
6918
    } else if (row.ts == pRateInfo->lastKey) {
417,524!
6919
      return TSDB_CODE_FUNC_DUP_TIMESTAMP;
×
6920
    }
6921

6922
    if ((INT64_MIN == pRateInfo->firstKey) || row.ts > pRateInfo->firstKey) {
417,524!
UNCOV
6923
      doSaveRateInfo(pRateInfo, true, row.ts, row.pPk, v);
×
6924
    } else if (row.ts == pRateInfo->firstKey) {
418,543!
6925
      return TSDB_CODE_FUNC_DUP_TIMESTAMP;
×
6926
    }
6927
  }
6928

6929
  numOfElems++;
7,778,845✔
6930

6931
  SET_VAL(pResInfo, numOfElems, 1);
7,778,845!
6932
  return TSDB_CODE_SUCCESS;
7,778,845✔
6933
}
6934

6935
static double doCalcRate(const SRateInfo* pRateInfo, double tickPerSec) {
7,756,221✔
6936
  if ((INT64_MIN == pRateInfo->lastKey) || (INT64_MIN == pRateInfo->firstKey) ||
7,756,221✔
6937
      (pRateInfo->firstKey >= pRateInfo->lastKey)) {
693,674!
6938
    return 0.0;
7,062,547✔
6939
  }
6940

6941
  double diff = 0;
693,674✔
6942
  // If the previous value of the last is greater than the last value, only keep the last point instead of the delta
6943
  // value between two values.
6944
  diff = pRateInfo->lastValue;
693,674✔
6945
  if (diff >= pRateInfo->firstValue) {
693,674✔
6946
    diff -= pRateInfo->firstValue;
364,522✔
6947
  }
6948

6949
  int64_t duration = pRateInfo->lastKey - pRateInfo->firstKey;
693,674✔
6950
  if (duration == 0) {
693,674!
6951
    return 0;
×
6952
  }
6953

6954
  return (duration > 0) ? ((double)diff) / (duration / tickPerSec) : 0.0;
693,674!
6955
}
6956

6957
static void irateTransferInfoImpl(TSKEY inputKey, SRateInfo* pInput, SRateInfo* pOutput, bool isFirstKey) {
402✔
6958
  if (inputKey > pOutput->lastKey) {
402✔
6959
    doSaveRateInfo(pOutput, true, pOutput->lastKey, pOutput->lastPk, pOutput->lastValue);
172✔
6960
    if (isFirstKey) {
172✔
6961
      doSaveRateInfo(pOutput, false, pInput->firstKey, pInput->firstPk, pInput->firstValue);
40✔
6962
    } else {
6963
      doSaveRateInfo(pOutput, false, pInput->lastKey, pInput->lastPk, pInput->lastValue);
132✔
6964
    }
6965
  } else if ((inputKey < pOutput->lastKey) && (inputKey > pOutput->firstKey)) {
230!
6966
    if (isFirstKey) {
128✔
6967
      doSaveRateInfo(pOutput, true, pInput->firstKey, pInput->firstPk, pInput->firstValue);
88✔
6968
    } else {
6969
      doSaveRateInfo(pOutput, true, pInput->lastKey, pInput->lastPk, pInput->lastValue);
40✔
6970
    }
6971
  } else {
6972
    // inputKey < pOutput->firstKey
6973
  }
6974
}
402✔
6975

6976
static void irateCopyInfo(SRateInfo* pInput, SRateInfo* pOutput) {
2,355,595✔
6977
  doSaveRateInfo(pOutput, true, pInput->firstKey, pInput->firstPk, pInput->firstValue);
2,355,595✔
6978
  doSaveRateInfo(pOutput, false, pInput->lastKey, pInput->lastPk, pInput->lastValue);
2,355,595✔
6979
}
2,355,595✔
6980

6981
static int32_t irateTransferInfo(SRateInfo* pInput, SRateInfo* pOutput) {
2,355,796✔
6982
  if ((pInput->firstKey != INT64_MIN &&
2,355,796✔
6983
       (pInput->firstKey == pOutput->firstKey || pInput->firstKey == pOutput->lastKey)) ||
125,941!
6984
      (pInput->lastKey != INT64_MIN && (pInput->lastKey == pOutput->firstKey || pInput->lastKey == pOutput->lastKey))) {
2,355,796!
6985
    return TSDB_CODE_FUNC_DUP_TIMESTAMP;
×
6986
  }
6987

6988
  if (pOutput->hasResult == 0) {
2,355,796✔
6989
    irateCopyInfo(pInput, pOutput);
2,355,595✔
6990
    pOutput->hasResult = pInput->hasResult;
2,355,595✔
6991
    return TSDB_CODE_SUCCESS;
2,355,595✔
6992
  }
6993

6994
  if (pInput->firstKey != INT64_MIN) {
201!
6995
    irateTransferInfoImpl(pInput->firstKey, pInput, pOutput, true);
201✔
6996
  }
6997

6998
  if (pInput->lastKey != INT64_MIN) {
201!
6999
    irateTransferInfoImpl(pInput->lastKey, pInput, pOutput, false);
201✔
7000
  }
7001

7002
  pOutput->hasResult = pInput->hasResult;
201✔
7003
  return TSDB_CODE_SUCCESS;
201✔
7004
}
7005

7006
int32_t irateFunctionMerge(SqlFunctionCtx* pCtx) {
2,355,804✔
7007
  SInputColumnInfoData* pInput = &pCtx->input;
2,355,804✔
7008
  SColumnInfoData*      pCol = pInput->pData[0];
2,355,804✔
7009
  if (pCol->info.type != TSDB_DATA_TYPE_BINARY) {
2,355,804!
7010
    return TSDB_CODE_FUNC_FUNTION_PARA_TYPE;
×
7011
  }
7012

7013
  SRateInfo* pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
2,355,804✔
7014
  initializeRateInfo(pCtx, pInfo, true);
2,355,804✔
7015

7016
  int32_t start = pInput->startRowIndex;
2,355,804✔
7017
  for (int32_t i = start; i < start + pInput->numOfRows; ++i) {
4,711,608✔
7018
    char*      data = colDataGetData(pCol, i);
2,355,804!
7019
    SRateInfo* pInputInfo = (SRateInfo*)varDataVal(data);
2,355,804✔
7020
    initializeRateInfo(pCtx, pInfo, true);
2,355,804✔
7021
    if (pInputInfo->hasResult) {
2,355,804✔
7022
      int32_t code = irateTransferInfo(pInputInfo, pInfo);
2,355,796✔
7023
      if (code != TSDB_CODE_SUCCESS) {
2,355,796!
7024
        return code;
×
7025
      }
7026
    }
7027
  }
7028

7029
  if (pInfo->hasResult) {
2,355,804✔
7030
    GET_RES_INFO(pCtx)->numOfRes = 1;
2,355,796✔
7031
  }
7032

7033
  return TSDB_CODE_SUCCESS;
2,355,804✔
7034
}
7035

7036
int32_t iratePartialFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
2,357,365✔
7037
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
2,357,365✔
7038
  SRateInfo*           pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
2,357,365✔
7039
  int32_t              resultBytes = getIrateInfoSize(pInfo->pkBytes);
2,357,365✔
7040
  char*                res = taosMemoryCalloc(resultBytes + VARSTR_HEADER_SIZE, sizeof(char));
2,357,365!
7041

7042
  if (NULL == res) {
2,357,366!
7043
    return terrno;
×
7044
  }
7045
  (void)memcpy(varDataVal(res), pInfo, resultBytes);
2,357,366✔
7046
  varDataSetLen(res, resultBytes);
2,357,366✔
7047

7048
  int32_t          slotId = pCtx->pExpr->base.resSchema.slotId;
2,357,366✔
7049
  SColumnInfoData* pCol = taosArrayGet(pBlock->pDataBlock, slotId);
2,357,366✔
7050
  if (NULL == pCol) {
2,357,366!
7051
    taosMemoryFree(res);
×
7052
    return TSDB_CODE_OUT_OF_RANGE;
×
7053
  }
7054

7055
  int32_t code = colDataSetVal(pCol, pBlock->info.rows, res, false);
2,357,366✔
7056

7057
  taosMemoryFree(res);
2,357,366!
7058
  return code;
2,357,366✔
7059
}
7060

7061
int32_t irateFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
7,756,352✔
7062
  int32_t          slotId = pCtx->pExpr->base.resSchema.slotId;
7,756,352✔
7063
  SColumnInfoData* pCol = taosArrayGet(pBlock->pDataBlock, slotId);
7,756,352✔
7064
  if (NULL == pCol) {
7,756,205!
7065
    return TSDB_CODE_OUT_OF_RANGE;
×
7066
  }
7067

7068
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
7,756,205✔
7069
  pResInfo->isNullRes = (pResInfo->numOfRes == 0) ? 1 : 0;
7,756,205✔
7070

7071
  SRateInfo* pInfo = GET_ROWCELL_INTERBUF(pResInfo);
7,756,205✔
7072
  double     result = doCalcRate(pInfo, (double)TSDB_TICK_PER_SECOND(pCtx->param[1].param.i));
7,756,205!
7073
  int32_t    code = colDataSetVal(pCol, pBlock->info.rows, (const char*)&result, pResInfo->isNullRes);
7,756,197✔
7074

7075
  return code;
7,756,134✔
7076
}
7077

7078
int32_t groupConstValueFunction(SqlFunctionCtx* pCtx) {
104,999,959✔
7079
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
104,999,959✔
7080
  SGroupKeyInfo*       pInfo = GET_ROWCELL_INTERBUF(pResInfo);
104,999,959✔
7081

7082
  SInputColumnInfoData* pInput = &pCtx->input;
104,999,959✔
7083
  SColumnInfoData*      pInputCol = pInput->pData[0];
104,999,959✔
7084

7085
  int32_t startIndex = pInput->startRowIndex;
104,999,959✔
7086

7087
  // escape rest of data blocks to avoid first entry to be overwritten.
7088
  if (pInfo->hasResult) {
104,999,959✔
7089
    goto _group_value_over;
10,589,826✔
7090
  }
7091

7092
  if (pInputCol->pData == NULL || colDataIsNull_s(pInputCol, startIndex)) {
188,384,202✔
7093
    pInfo->isNull = true;
2,678,566✔
7094
    pInfo->hasResult = true;
2,678,566✔
7095
    goto _group_value_over;
2,678,566✔
7096
  }
7097

7098
  char* data = colDataGetData(pInputCol, startIndex);
91,731,567!
7099
  if (IS_VAR_DATA_TYPE(pInputCol->info.type)) {
91,731,567!
7100
    (void)memcpy(pInfo->data, data,
71,878,384✔
7101
                 (pInputCol->info.type == TSDB_DATA_TYPE_JSON) ? getJsonValueLen(data) : varDataTLen(data));
71,878,384✔
7102
  } else {
7103
    (void)memcpy(pInfo->data, data, pInputCol->info.bytes);
19,853,183✔
7104
  }
7105
  pInfo->hasResult = true;
91,731,567✔
7106

7107
_group_value_over:
104,999,959✔
7108

7109
  SET_VAL(pResInfo, 1, 1);
104,999,959✔
7110
  return TSDB_CODE_SUCCESS;
104,999,959✔
7111
}
7112

7113
int32_t groupKeyFunction(SqlFunctionCtx* pCtx) { return groupConstValueFunction(pCtx); }
105,017,173✔
7114

7115
int32_t groupConstValueFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
92,947,607✔
7116
  int32_t          slotId = pCtx->pExpr->base.resSchema.slotId;
92,947,607✔
7117
  int32_t          code = TSDB_CODE_SUCCESS;
92,947,607✔
7118
  SColumnInfoData* pCol = taosArrayGet(pBlock->pDataBlock, slotId);
92,947,607✔
7119
  if (NULL == pCol) {
92,916,525!
7120
    return TSDB_CODE_OUT_OF_RANGE;
×
7121
  }
7122

7123
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
92,916,525✔
7124

7125
  SGroupKeyInfo* pInfo = GET_ROWCELL_INTERBUF(pResInfo);
92,916,525✔
7126

7127
  if (pInfo->hasResult) {
92,916,525!
7128
    int32_t currentRow = pBlock->info.rows;
92,975,550✔
7129
    for (; currentRow < pBlock->info.rows + pResInfo->numOfRes; ++currentRow) {
186,667,623✔
7130
      code = colDataSetVal(pCol, currentRow, pInfo->data, pInfo->isNull ? true : false);
92,956,987✔
7131
      if (TSDB_CODE_SUCCESS != code) {
93,692,073!
7132
        return code;
×
7133
      }
7134
    }
7135
  } else {
7136
    pResInfo->numOfRes = 0;
×
7137
  }
7138

7139
  return code;
93,651,611✔
7140
}
7141

7142
int32_t groupKeyFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) { return groupConstValueFinalize(pCtx, pBlock); }
92,938,004✔
7143

7144
int32_t groupKeyCombine(SqlFunctionCtx* pDestCtx, SqlFunctionCtx* pSourceCtx) {
×
7145
  SResultRowEntryInfo* pDResInfo = GET_RES_INFO(pDestCtx);
×
7146
  SGroupKeyInfo*       pDBuf = GET_ROWCELL_INTERBUF(pDResInfo);
×
7147

7148
  SResultRowEntryInfo* pSResInfo = GET_RES_INFO(pSourceCtx);
×
7149
  SGroupKeyInfo*       pSBuf = GET_ROWCELL_INTERBUF(pSResInfo);
×
7150

7151
  // escape rest of data blocks to avoid first entry to be overwritten.
7152
  if (pDBuf->hasResult) {
×
7153
    goto _group_key_over;
×
7154
  }
7155

7156
  if (pSBuf->isNull) {
×
7157
    pDBuf->isNull = true;
×
7158
    pDBuf->hasResult = true;
×
7159
    goto _group_key_over;
×
7160
  }
7161

7162
  if (IS_VAR_DATA_TYPE(pSourceCtx->resDataInfo.type)) {
×
7163
    (void)memcpy(pDBuf->data, pSBuf->data,
×
7164
                 (pSourceCtx->resDataInfo.type == TSDB_DATA_TYPE_JSON) ? getJsonValueLen(pSBuf->data)
×
7165
                                                                       : varDataTLen(pSBuf->data));
×
7166
  } else {
7167
    (void)memcpy(pDBuf->data, pSBuf->data, pSourceCtx->resDataInfo.bytes);
×
7168
  }
7169

7170
  pDBuf->hasResult = true;
×
7171

7172
_group_key_over:
×
7173

7174
  SET_VAL(pDResInfo, 1, 1);
×
7175
  return TSDB_CODE_SUCCESS;
×
7176
}
7177

7178
int32_t cachedLastRowFunction(SqlFunctionCtx* pCtx) {
3,123✔
7179
  int32_t numOfElems = 0;
3,123✔
7180

7181
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
3,123✔
7182
  SFirstLastRes*       pInfo = GET_ROWCELL_INTERBUF(pResInfo);
3,123✔
7183

7184
  SInputColumnInfoData* pInput = &pCtx->input;
3,123✔
7185
  SColumnInfoData*      pInputCol = pInput->pData[0];
3,123✔
7186

7187
  int32_t bytes = pInputCol->info.bytes;
3,123✔
7188
  pInfo->bytes = bytes;
3,123✔
7189

7190
  SColumnInfoData* pkCol = pInput->pPrimaryKey;
3,123✔
7191
  pInfo->pkType = -1;
3,123✔
7192
  __compar_fn_t pkCompareFn = NULL;
3,123✔
7193
  if (pCtx->hasPrimaryKey) {
3,123✔
7194
    pInfo->pkType = pkCol->info.type;
20✔
7195
    pInfo->pkBytes = pkCol->info.bytes;
20✔
7196
    pkCompareFn = getKeyComparFunc(pInfo->pkType, TSDB_ORDER_DESC);
20✔
7197
  }
7198

7199
  // TODO it traverse the different way.
7200
  // last_row function does not ignore the null value
7201
  for (int32_t i = pInput->numOfRows + pInput->startRowIndex - 1; i >= pInput->startRowIndex; --i) {
6,255✔
7202
    numOfElems++;
3,133✔
7203

7204
    bool  isNull = colDataIsNull(pInputCol, pInput->numOfRows, i, NULL);
3,133✔
7205
    char* data = isNull ? NULL : colDataGetData(pInputCol, i);
3,133!
7206

7207
    TSKEY cts = getRowPTs(pInput->pPTS, i);
3,133!
7208
    if (pResInfo->numOfRes == 0 || pInfo->ts < cts) {
3,133✔
7209
      int32_t code = doSaveLastrow(pCtx, data, i, cts, pInfo);
2,783✔
7210
      if (code != TSDB_CODE_SUCCESS) {
2,782!
7211
        return code;
×
7212
      }
7213
      pResInfo->numOfRes = 1;
2,782✔
7214
    }
7215
  }
7216

7217
  SET_VAL(pResInfo, numOfElems, 1);
3,122!
7218
  return TSDB_CODE_SUCCESS;
3,122✔
7219
}
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