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

taosdata / TDengine / #3561

19 Dec 2024 03:15AM UTC coverage: 58.812% (-1.3%) from 60.124%
#3561

push

travis-ci

web-flow
Merge pull request #29213 from taosdata/merge/mainto3.0

merge: from main to 3.0 branch

130770 of 287658 branches covered (45.46%)

Branch coverage included in aggregate %.

32 of 78 new or added lines in 4 files covered. (41.03%)

7347 existing lines in 166 files now uncovered.

205356 of 283866 relevant lines covered (72.34%)

7187865.64 hits per line

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

71.54
/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; }
19,740,128✔
32
bool ignoreNull(int8_t ignoreOption) { return (ignoreOption & 0x2) == 0x2; }
223,527✔
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) {
295,772✔
194
  SFuncInputRowIter* pIter = &pCtx->rowIter;
295,772✔
195

196
  if (!pCtx->bInputFinished) {
295,772!
197
    pIter->pInput = &pCtx->input;
295,773✔
198
    pIter->tsList = (TSKEY*)pIter->pInput->pPTS->pData;
295,773✔
199
    pIter->pDataCol = pIter->pInput->pData[0];
295,773✔
200
    pIter->pPkCol = pIter->pInput->pPrimaryKey;
295,773✔
201
    pIter->rowIndex = pIter->pInput->startRowIndex;
295,773✔
202
    pIter->inputEndIndex = pIter->rowIndex + pIter->pInput->numOfRows - 1;
295,773✔
203
    pIter->pSrcBlock = pCtx->pSrcBlock;
295,773✔
204
    if (!pIter->hasGroupId || pIter->groupId != pIter->pSrcBlock->info.id.groupId) {
295,773✔
205
      pIter->hasGroupId = true;
43,079✔
206
      pIter->groupId = pIter->pSrcBlock->info.id.groupId;
43,079✔
207
      pIter->hasPrev = false;
43,079✔
208
    }
209
  } else {
210
    pIter->finalRow = true;
×
211
  }
212
}
295,772✔
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) {
17,025,414✔
337
  pRow->ts = pIter->tsList[rowIndex];
17,025,414✔
338
  pRow->ts = pIter->tsList[rowIndex];
17,025,414✔
339
  pRow->isDataNull = colDataIsNull_f(pIter->pDataCol->nullbitmap, rowIndex);
17,025,414✔
340
  pRow->pData = colDataGetData(pIter->pDataCol, rowIndex);
17,025,414!
341
  pRow->pPk = setPk ? colDataGetData(pIter->pPkCol, rowIndex) : NULL;
17,025,414!
342
  pRow->block = pIter->pSrcBlock;
17,025,414✔
343
  pRow->rowIndex = rowIndex;
17,025,414✔
344
}
17,025,414✔
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) {
17,334,726✔
383
  if (pIter->rowIndex <= pIter->inputEndIndex) {
17,334,726✔
384
    setInputRowInfo(pRow, pIter, pIter->rowIndex, false);
17,025,132✔
385
    ++pIter->rowIndex;
17,026,499✔
386
    return true;
17,026,499✔
387
  } else {
388
    return false;
309,594✔
389
  }
390
}
391

392
int32_t funcInputGetNextRow(SqlFunctionCtx* pCtx, SFuncInputRow* pRow, bool* res) {
17,335,673✔
393
  SFuncInputRowIter* pIter = &pCtx->rowIter;
17,335,673✔
394
  if (pCtx->hasPrimaryKey) {
17,335,673✔
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);
17,335,343✔
403
    return TSDB_CODE_SUCCESS;
17,336,115✔
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) {
15,702,939✔
411
  if (pCtx->subsidiaries.num <= 0) {
15,702,939!
412
    return TSDB_CODE_SUCCESS;
×
413
  }
414

415
  for (int32_t j = 0; j < pCtx->subsidiaries.num; ++j) {
46,825,018✔
416
    SqlFunctionCtx* pc = pCtx->subsidiaries.pCtx[j];
31,122,079✔
417

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

422
    SColumnInfoData* pSrcCol = taosArrayGet(pSrcBlock->pDataBlock, srcSlotId);
31,122,079✔
423
    if (NULL == pSrcCol) {
31,122,079!
424
      return TSDB_CODE_OUT_OF_RANGE;
×
425
    }
426

427
    char* pData = colDataGetData(pSrcCol, rowIndex);
31,122,079!
428

429
    // append to dest col
430
    int32_t dstSlotId = pc->pExpr->base.resSchema.slotId;
31,122,079✔
431

432
    SColumnInfoData* pDstCol = taosArrayGet(pCtx->pDstBlock->pDataBlock, dstSlotId);
31,122,079✔
433
    if (NULL == pDstCol) {
31,122,079!
434
      return TSDB_CODE_OUT_OF_RANGE;
×
435
    }
436
    if (colDataIsNull_s(pSrcCol, rowIndex) == true) {
62,244,158✔
437
      colDataSetNULL(pDstCol, pos);
1,548,060✔
438
    } else {
439
      int32_t code = colDataSetVal(pDstCol, pos, pData, false);
29,574,019✔
440
      if (TSDB_CODE_SUCCESS != code) {
29,574,019!
441
        return code;
×
442
      }
443
    }
444
  }
445
  return TSDB_CODE_SUCCESS;
15,702,939✔
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) {
276,336,806✔
454
  if (pResultInfo->initialized) {
276,336,806✔
455
    return TSDB_CODE_SUCCESS;  // already initialized
12,432✔
456
  }
457

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

462
  initResultRowEntry(pResultInfo, pCtx->resDataInfo.interBufSize);
276,324,374✔
463
  return TSDB_CODE_SUCCESS;
276,324,374✔
464
}
465

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

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

479
  return code;
122,608,054✔
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) {
138,331✔
513
  SNode* pParam = nodesListGetNode(pFunc->pParameterList, 0);
138,331✔
514
  if (QUERY_NODE_COLUMN == nodeType(pParam) && PRIMARYKEY_TIMESTAMP_COL_ID == ((SColumnNode*)pParam)->colId) {
138,336✔
515
    return FUNC_DATA_REQUIRED_NOT_LOAD;
72,057✔
516
  }
517
  return FUNC_DATA_REQUIRED_SMA_LOAD;
66,279✔
518
}
519

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

525
static int64_t getNumOfElems(SqlFunctionCtx* pCtx) {
95,292,462✔
526
  int64_t numOfElem = 0;
95,292,462✔
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;
95,292,462✔
534
  SColumnInfoData*      pInputCol = pInput->pData[0];
95,292,462✔
535
  if (1 == pInput->numOfRows && pInput->blankFill) {
95,292,462✔
536
    return 0;
404,767✔
537
  }
538
  if (pInput->colDataSMAIsSet && pInput->totalRows == pInput->numOfRows) {
94,887,695!
539
    numOfElem = pInput->numOfRows - pInput->pColumnDataAgg[0]->numOfNull;
3,076✔
540
  } else {
541
    if (pInputCol->hasNull) {
94,884,619✔
542
      for (int32_t i = pInput->startRowIndex; i < pInput->startRowIndex + pInput->numOfRows; ++i) {
231,354,625✔
543
        if (colDataIsNull(pInputCol, pInput->totalRows, i, NULL)) {
412,510,548!
544
          continue;
1,853,433✔
545
        }
546
        numOfElem += 1;
204,401,841✔
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;
69,785,268✔
552
    }
553
  }
554
  return numOfElem;
94,887,695✔
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) {
95,338,941✔
562
  int64_t numOfElem = 0;
95,338,941✔
563

564
  SResultRowEntryInfo*  pResInfo = GET_RES_INFO(pCtx);
95,338,941✔
565
  SInputColumnInfoData* pInput = &pCtx->input;
95,338,941✔
566

567
  int32_t type = pInput->pData[0]->info.type;
95,338,941✔
568

569
  char* buf = GET_ROWCELL_INTERBUF(pResInfo);
95,338,941✔
570
  if (IS_NULL_TYPE(type)) {
95,338,941✔
571
    // select count(NULL) returns 0
572
    numOfElem = 1;
11,707✔
573
    *((int64_t*)buf) += 0;
11,707✔
574
  } else {
575
    numOfElem = getNumOfElems(pCtx);
95,327,234✔
576
    *((int64_t*)buf) += numOfElem;
94,894,784✔
577
  }
578

579
  if (tsCountAlwaysReturnValue) {
94,906,491!
580
    pResInfo->numOfRes = 1;
95,004,709✔
581
  } else {
582
    SET_VAL(pResInfo, *((int64_t*)buf), 1);
×
583
  }
584

585
  return TSDB_CODE_SUCCESS;
94,906,491✔
586
}
587

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

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

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

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

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

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

613
int32_t sumFunction(SqlFunctionCtx* pCtx) {
73,323,470✔
614
  int32_t numOfElem = 0;
73,323,470✔
615

616
  // Only the pre-computing information loaded and actual data does not loaded
617
  SInputColumnInfoData* pInput = &pCtx->input;
73,323,470✔
618
  SColumnDataAgg*       pAgg = pInput->pColumnDataAgg[0];
73,323,470✔
619
  int32_t               type = pInput->pData[0]->info.type;
73,323,470✔
620

621
  SSumRes* pSumRes = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
73,323,470✔
622
  pSumRes->type = type;
73,323,470✔
623

624
  if (IS_NULL_TYPE(type)) {
73,323,470✔
625
    numOfElem = 0;
226✔
626
    goto _sum_over;
226✔
627
  }
628

629
  if (pInput->colDataSMAIsSet) {
73,323,244✔
630
    numOfElem = pInput->numOfRows - pAgg->numOfNull;
543✔
631

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

642
    int32_t start = pInput->startRowIndex;
73,322,701✔
643
    int32_t numOfRows = pInput->numOfRows;
73,322,701✔
644

645
    if (IS_SIGNED_NUMERIC_TYPE(type) || type == TSDB_DATA_TYPE_BOOL) {
73,322,701!
646
      if (type == TSDB_DATA_TYPE_TINYINT || type == TSDB_DATA_TYPE_BOOL) {
73,199,561!
647
        LIST_ADD_N(pSumRes->isum, pCol, start, numOfRows, int8_t, numOfElem);
1,340,984✔
648
      } else if (type == TSDB_DATA_TYPE_SMALLINT) {
72,832,888✔
649
        LIST_ADD_N(pSumRes->isum, pCol, start, numOfRows, int16_t, numOfElem);
239,078✔
650
      } else if (type == TSDB_DATA_TYPE_INT) {
72,788,089✔
651
        LIST_ADD_N(pSumRes->isum, pCol, start, numOfRows, int32_t, numOfElem);
269,957,087✔
652
      } else if (type == TSDB_DATA_TYPE_BIGINT) {
17,876,153✔
653
        LIST_ADD_N(pSumRes->isum, pCol, start, numOfRows, int64_t, numOfElem);
69,234,147✔
654
      }
655
    } else if (IS_UNSIGNED_NUMERIC_TYPE(type)) {
123,140!
656
      if (type == TSDB_DATA_TYPE_UTINYINT) {
82✔
657
        LIST_ADD_N(pSumRes->usum, pCol, start, numOfRows, uint8_t, numOfElem);
30,009!
658
      } else if (type == TSDB_DATA_TYPE_USMALLINT) {
73✔
659
        LIST_ADD_N(pSumRes->usum, pCol, start, numOfRows, uint16_t, numOfElem);
30,017✔
660
      } else if (type == TSDB_DATA_TYPE_UINT) {
63✔
661
        LIST_ADD_N(pSumRes->usum, pCol, start, numOfRows, uint32_t, numOfElem);
30,009!
662
      } else if (type == TSDB_DATA_TYPE_UBIGINT) {
54!
663
        LIST_ADD_N(pSumRes->usum, pCol, start, numOfRows, uint64_t, numOfElem);
30,594✔
664
      }
665
    } else if (type == TSDB_DATA_TYPE_DOUBLE) {
123,058✔
666
      LIST_ADD_N(pSumRes->dsum, pCol, start, numOfRows, double, numOfElem);
1,984,498✔
667
    } else if (type == TSDB_DATA_TYPE_FLOAT) {
42,174✔
668
      LIST_ADD_N(pSumRes->dsum, pCol, start, numOfRows, float, numOfElem);
244,003✔
669
    }
670
  }
671

672
  // check for overflow
673
  if (IS_FLOAT_TYPE(type) && (isinf(pSumRes->dsum) || isnan(pSumRes->dsum))) {
73,323,244!
674
    numOfElem = 0;
×
675
  }
676

677
_sum_over:
73,658,614✔
678
  if (numOfElem == 0) {
73,323,470✔
679
    if (tsCountAlwaysReturnValue && pCtx->pExpr->pExpr->_function.pFunctNode->hasOriginalFunc &&
97,065✔
680
        fmIsCountLikeFunc(pCtx->pExpr->pExpr->_function.pFunctNode->originalFuncId)) {
11,390✔
681
      numOfElem = 1;
36✔
682
    }
683
  }
684
  // data in the check operation are all null, not output
685
  SET_VAL(GET_RES_INFO(pCtx), numOfElem, 1);
73,323,470✔
686
  return TSDB_CODE_SUCCESS;
73,323,470✔
687
}
688

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

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

698
  SSumRes* pSumRes = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
699

700
  if (pInput->colDataSMAIsSet) {
701
    numOfElem = pInput->numOfRows - pAgg->numOfNull;
702

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

713
    int32_t start = pInput->startRowIndex;
714
    int32_t numOfRows = pInput->numOfRows;
715

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

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

749
int32_t sumCombine(SqlFunctionCtx* pDestCtx, SqlFunctionCtx* pSourceCtx) {
47✔
750
  SResultRowEntryInfo* pDResInfo = GET_RES_INFO(pDestCtx);
47✔
751
  SSumRes*             pDBuf = GET_ROWCELL_INTERBUF(pDResInfo);
47✔
752

753
  SResultRowEntryInfo* pSResInfo = GET_RES_INFO(pSourceCtx);
47✔
754
  SSumRes*             pSBuf = GET_ROWCELL_INTERBUF(pSResInfo);
47✔
755
  int16_t              type = pDBuf->type == TSDB_DATA_TYPE_NULL ? pSBuf->type : pDBuf->type;
47✔
756

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

769
bool getSumFuncEnv(SFunctionNode* UNUSED_PARAM(pFunc), SFuncExecEnv* pEnv) {
153,627✔
770
  pEnv->calcMemSize = sizeof(SSumRes);
153,627✔
771
  return true;
153,627✔
772
}
773

774
EFuncDataRequired statisDataRequired(SFunctionNode* pFunc, STimeWindow* pTimeWindow) {
209,847✔
775
  return FUNC_DATA_REQUIRED_SMA_LOAD;
209,847✔
776
}
777

778
int32_t minmaxFunctionSetup(SqlFunctionCtx* pCtx, SResultRowEntryInfo* pResultInfo) {
40,164,804✔
779
  if (pResultInfo->initialized) {
40,164,804!
780
    return TSDB_CODE_SUCCESS;
×
781
  }
782
  if (TSDB_CODE_SUCCESS != functionSetup(pCtx, pResultInfo)) {
40,164,804!
783
    return TSDB_CODE_FUNC_SETUP_ERROR;  // not initialized since it has been initialized
×
784
  }
785

786
  SMinmaxResInfo* buf = GET_ROWCELL_INTERBUF(pResultInfo);
40,192,535✔
787
  buf->assign = false;
40,192,535✔
788
  buf->tuplePos.pageId = -1;
40,192,535✔
789

790
  buf->nullTupleSaved = false;
40,192,535✔
791
  buf->nullTuplePos.pageId = -1;
40,192,535✔
792
  buf->str = NULL;
40,192,535✔
793
  return TSDB_CODE_SUCCESS;
40,192,535✔
794
}
795

796
bool getMinmaxFuncEnv(SFunctionNode* UNUSED_PARAM(pFunc), SFuncExecEnv* pEnv) {
194,192✔
797
  pEnv->calcMemSize = sizeof(SMinmaxResInfo);
194,192✔
798
  return true;
194,192✔
799
}
800

801
int32_t minFunction(SqlFunctionCtx* pCtx) {
21,725,487✔
802
  int32_t numOfElems = 0;
21,725,487✔
803
  int32_t code = doMinMaxHelper(pCtx, 1, &numOfElems);
21,725,487✔
804
  if (code != TSDB_CODE_SUCCESS) {
21,902,875!
805
    return code;
×
806
  }
807
  SET_VAL(GET_RES_INFO(pCtx), numOfElems, 1);
21,902,875✔
808
  return TSDB_CODE_SUCCESS;
21,902,875✔
809
}
810

811
int32_t maxFunction(SqlFunctionCtx* pCtx) {
21,870,753✔
812
  int32_t numOfElems = 0;
21,870,753✔
813
  int32_t code = doMinMaxHelper(pCtx, 0, &numOfElems);
21,870,753✔
814
  if (code != TSDB_CODE_SUCCESS) {
21,995,587!
815
    return code;
×
816
  }
817
  SET_VAL(GET_RES_INFO(pCtx), numOfElems, 1);
21,995,587✔
818
  return TSDB_CODE_SUCCESS;
21,995,587✔
819
}
820

821
static int32_t setNullSelectivityValue(SqlFunctionCtx* pCtx, SSDataBlock* pBlock, int32_t rowIndex);
822
static int32_t setSelectivityValue(SqlFunctionCtx* pCtx, SSDataBlock* pBlock, const STuplePos* pTuplePos,
823
                                   int32_t rowIndex);
824

825
int32_t minmaxFunctionFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
39,634,055✔
826
  int32_t code = TSDB_CODE_SUCCESS;
39,634,055✔
827

828
  SResultRowEntryInfo* pEntryInfo = GET_RES_INFO(pCtx);
39,634,055✔
829
  SMinmaxResInfo*      pRes = GET_ROWCELL_INTERBUF(pEntryInfo);
39,634,055✔
830

831
  int32_t slotId = pCtx->pExpr->base.resSchema.slotId;
39,634,055✔
832
  int32_t currentRow = pBlock->info.rows;
39,634,055✔
833

834
  SColumnInfoData* pCol = taosArrayGet(pBlock->pDataBlock, slotId);
39,634,055✔
835
  if (NULL == pCol) {
39,641,805!
836
    return TSDB_CODE_OUT_OF_RANGE;
×
837
  }
838
  pEntryInfo->isNullRes = (pEntryInfo->numOfRes == 0) ? 1 : 0;
39,641,805✔
839

840
  // NOTE: do nothing change it, for performance issue
841
  if (!pEntryInfo->isNullRes) {
39,641,805✔
842
    switch (pCol->info.type) {
32,173,418!
843
      case TSDB_DATA_TYPE_UBIGINT:
12,130,490✔
844
      case TSDB_DATA_TYPE_BIGINT:
845
        ((int64_t*)pCol->pData)[currentRow] = pRes->v;
12,130,490✔
846
        break;
12,130,490✔
847
      case TSDB_DATA_TYPE_UINT:
19,726,461✔
848
      case TSDB_DATA_TYPE_INT:
849
        colDataSetInt32(pCol, currentRow, (int32_t*)&pRes->v);
19,726,461✔
850
        break;
19,726,461✔
851
      case TSDB_DATA_TYPE_USMALLINT:
179,367✔
852
      case TSDB_DATA_TYPE_SMALLINT:
853
        colDataSetInt16(pCol, currentRow, (int16_t*)&pRes->v);
179,367✔
854
        break;
179,367✔
855
      case TSDB_DATA_TYPE_BOOL:
179,185✔
856
      case TSDB_DATA_TYPE_UTINYINT:
857
      case TSDB_DATA_TYPE_TINYINT:
858
        colDataSetInt8(pCol, currentRow, (int8_t*)&pRes->v);
179,185✔
859
        break;
179,185✔
860
      case TSDB_DATA_TYPE_DOUBLE:
5,049✔
861
        colDataSetDouble(pCol, currentRow, (double*)&pRes->v);
5,049✔
862
        break;
5,049✔
863
      case TSDB_DATA_TYPE_FLOAT: {
2,637✔
864
        float v = GET_FLOAT_VAL(&pRes->v);
2,637✔
865
        colDataSetFloat(pCol, currentRow, &v);
2,637✔
866
        break;
2,637✔
867
      }
868
      case TSDB_DATA_TYPE_VARBINARY:
384✔
869
      case TSDB_DATA_TYPE_VARCHAR:
870
      case TSDB_DATA_TYPE_NCHAR: {
871
        code = colDataSetVal(pCol, currentRow, pRes->str, false);
384✔
872
        if (TSDB_CODE_SUCCESS != code) {
384!
873
          return code;
×
874
        }
875
        break;
384✔
876
      }
877
    }
878
  } else {
879
    colDataSetNULL(pCol, currentRow);
7,468,387!
880
  }
881

882
  taosMemoryFreeClear(pRes->str);
39,641,805!
883
  if (pCtx->subsidiaries.num > 0) {
39,641,805✔
884
    if (pEntryInfo->numOfRes > 0) {
81,402✔
885
      code = setSelectivityValue(pCtx, pBlock, &pRes->tuplePos, currentRow);
79,408✔
886
    } else {
887
      code = setSelectivityValue(pCtx, pBlock, &pRes->nullTuplePos, currentRow);
1,994✔
888
    }
889
  }
890

891
  return code;
39,657,613✔
892
}
893

894
#ifdef BUILD_NO_CALL
895
int32_t setNullSelectivityValue(SqlFunctionCtx* pCtx, SSDataBlock* pBlock, int32_t rowIndex) {
896
  if (pCtx->subsidiaries.num <= 0) {
897
    return TSDB_CODE_SUCCESS;
898
  }
899

900
  for (int32_t j = 0; j < pCtx->subsidiaries.num; ++j) {
901
    SqlFunctionCtx* pc = pCtx->subsidiaries.pCtx[j];
902
    int32_t         dstSlotId = pc->pExpr->base.resSchema.slotId;
903

904
    SColumnInfoData* pDstCol = taosArrayGet(pBlock->pDataBlock, dstSlotId);
905
    colDataSetNULL(pDstCol, rowIndex);
906
  }
907

908
  return TSDB_CODE_SUCCESS;
909
}
910
#endif
911

912
int32_t setSelectivityValue(SqlFunctionCtx* pCtx, SSDataBlock* pBlock, const STuplePos* pTuplePos, int32_t rowIndex) {
32,157,323✔
913
  if (pCtx->subsidiaries.num <= 0) {
32,157,323✔
914
    return TSDB_CODE_SUCCESS;
32,016,891✔
915
  }
916

917
  if ((pCtx->saveHandle.pBuf != NULL && pTuplePos->pageId != -1) ||
140,432!
918
      (pCtx->saveHandle.pState && pTuplePos->streamTupleKey.ts > 0)) {
63,969!
919
    int32_t numOfCols = pCtx->subsidiaries.num;
140,441✔
920
    char*   p = NULL;
140,441✔
921
    int32_t code = loadTupleData(pCtx, pTuplePos, &p);
140,441✔
922
    if (p == NULL || TSDB_CODE_SUCCESS != code) {
142,277!
923
      qError("Load tuple data failed since %s, groupId:%" PRIu64 ", ts:%" PRId64, terrstr(),
×
924
             pTuplePos->streamTupleKey.groupId, pTuplePos->streamTupleKey.ts);
925
      return TSDB_CODE_NOT_FOUND;
×
926
    }
927

928
    bool* nullList = (bool*)p;
142,279✔
929
    char* pStart = (char*)(nullList + numOfCols * sizeof(bool));
142,279✔
930

931
    // todo set the offset value to optimize the performance.
932
    for (int32_t j = 0; j < numOfCols; ++j) {
307,110✔
933
      SqlFunctionCtx* pc = pCtx->subsidiaries.pCtx[j];
164,788✔
934
      int32_t         dstSlotId = pc->pExpr->base.resSchema.slotId;
164,788✔
935

936
      // group_key function has its own process function
937
      // do not process there
938
      if (fmIsGroupKeyFunc(pc->functionId)) {
164,788✔
939
        continue;
22,279✔
940
      }
941

942
      SColumnInfoData* pDstCol = taosArrayGet(pBlock->pDataBlock, dstSlotId);
142,510✔
943
      if (NULL == pDstCol) {
142,507!
944
        return TSDB_CODE_OUT_OF_RANGE;
×
945
      }
946
      if (nullList[j]) {
142,507✔
947
        colDataSetNULL(pDstCol, rowIndex);
190!
948
      } else {
949
        code = colDataSetVal(pDstCol, rowIndex, pStart, false);
142,317✔
950
        if (TSDB_CODE_SUCCESS != code) {
142,362!
951
          return code;
×
952
        }
953
      }
954
      pStart += pDstCol->info.bytes;
142,552✔
955
    }
956
  }
957

958
  return TSDB_CODE_SUCCESS;
142,313✔
959
}
960

961
// This function append the selectivity to subsidiaries function context directly, without fetching data
962
// from intermediate disk based buf page
963
int32_t appendSelectivityValue(SqlFunctionCtx* pCtx, int32_t rowIndex, int32_t pos) {
2,656✔
964
  if (pCtx->subsidiaries.num <= 0) {
2,656!
965
    return TSDB_CODE_SUCCESS;
×
966
  }
967

968
  int32_t code = TSDB_CODE_SUCCESS;
2,656✔
969
  for (int32_t j = 0; j < pCtx->subsidiaries.num; ++j) {
7,058✔
970
    SqlFunctionCtx* pc = pCtx->subsidiaries.pCtx[j];
4,402✔
971

972
    // get data from source col
973
    SFunctParam* pFuncParam = &pc->pExpr->base.pParam[0];
4,402✔
974
    int32_t      srcSlotId = pFuncParam->pCol->slotId;
4,402✔
975

976
    SColumnInfoData* pSrcCol = taosArrayGet(pCtx->pSrcBlock->pDataBlock, srcSlotId);
4,402✔
977
    if (NULL == pSrcCol) {
4,402!
978
      return TSDB_CODE_OUT_OF_RANGE;
×
979
    }
980

981
    char* pData = colDataGetData(pSrcCol, rowIndex);
4,402!
982

983
    // append to dest col
984
    int32_t dstSlotId = pc->pExpr->base.resSchema.slotId;
4,402✔
985

986
    SColumnInfoData* pDstCol = taosArrayGet(pCtx->pDstBlock->pDataBlock, dstSlotId);
4,402✔
987
    if (NULL == pDstCol) {
4,402!
988
      return TSDB_CODE_OUT_OF_RANGE;
×
989
    }
990

991
    if (colDataIsNull_s(pSrcCol, rowIndex) == true) {
8,804✔
992
      colDataSetNULL(pDstCol, pos);
356✔
993
    } else {
994
      code = colDataSetVal(pDstCol, pos, pData, false);
4,046✔
995
      if (TSDB_CODE_SUCCESS != code) {
4,046!
996
        return code;
×
997
      }
998
    }
999
  }
1000
  return code;
2,656✔
1001
}
1002

1003
void replaceTupleData(STuplePos* pDestPos, STuplePos* pSourcePos) { *pDestPos = *pSourcePos; }
32✔
1004

1005
#define COMPARE_MINMAX_DATA(type) (((*(type*)&pDBuf->v) < (*(type*)&pSBuf->v)) ^ isMinFunc)
1006
int32_t minMaxCombine(SqlFunctionCtx* pDestCtx, SqlFunctionCtx* pSourceCtx, int32_t isMinFunc) {
58✔
1007
  SResultRowEntryInfo* pDResInfo = GET_RES_INFO(pDestCtx);
58✔
1008
  SMinmaxResInfo*      pDBuf = GET_ROWCELL_INTERBUF(pDResInfo);
58✔
1009

1010
  SResultRowEntryInfo* pSResInfo = GET_RES_INFO(pSourceCtx);
58✔
1011
  SMinmaxResInfo*      pSBuf = GET_ROWCELL_INTERBUF(pSResInfo);
58✔
1012
  int16_t              type = pDBuf->type == TSDB_DATA_TYPE_NULL ? pSBuf->type : pDBuf->type;
58✔
1013

1014
  switch (type) {
58!
1015
    case TSDB_DATA_TYPE_DOUBLE:
3✔
1016
    case TSDB_DATA_TYPE_UBIGINT:
1017
    case TSDB_DATA_TYPE_BIGINT:
1018
      if (pSBuf->assign && (COMPARE_MINMAX_DATA(int64_t) || !pDBuf->assign)) {
3!
1019
        pDBuf->v = pSBuf->v;
1✔
1020
        replaceTupleData(&pDBuf->tuplePos, &pSBuf->tuplePos);
1✔
1021
        pDBuf->assign = true;
1✔
1022
      }
1023
      break;
3✔
1024
    case TSDB_DATA_TYPE_UINT:
55✔
1025
    case TSDB_DATA_TYPE_INT:
1026
      if (pSBuf->assign && (COMPARE_MINMAX_DATA(int32_t) || !pDBuf->assign)) {
55!
1027
        pDBuf->v = pSBuf->v;
31✔
1028
        replaceTupleData(&pDBuf->tuplePos, &pSBuf->tuplePos);
31✔
1029
        pDBuf->assign = true;
31✔
1030
      }
1031
      break;
55✔
1032
    case TSDB_DATA_TYPE_USMALLINT:
×
1033
    case TSDB_DATA_TYPE_SMALLINT:
1034
      if (pSBuf->assign && (COMPARE_MINMAX_DATA(int16_t) || !pDBuf->assign)) {
×
1035
        pDBuf->v = pSBuf->v;
×
1036
        replaceTupleData(&pDBuf->tuplePos, &pSBuf->tuplePos);
×
1037
        pDBuf->assign = true;
×
1038
      }
1039
      break;
×
1040
    case TSDB_DATA_TYPE_BOOL:
×
1041
    case TSDB_DATA_TYPE_UTINYINT:
1042
    case TSDB_DATA_TYPE_TINYINT:
1043
      if (pSBuf->assign && (COMPARE_MINMAX_DATA(int8_t) || !pDBuf->assign)) {
×
1044
        pDBuf->v = pSBuf->v;
×
1045
        replaceTupleData(&pDBuf->tuplePos, &pSBuf->tuplePos);
×
1046
        pDBuf->assign = true;
×
1047
      }
1048
      break;
×
1049
    case TSDB_DATA_TYPE_FLOAT: {
×
1050
      if (pSBuf->assign && (COMPARE_MINMAX_DATA(double) || !pDBuf->assign)) {
×
1051
        pDBuf->v = pSBuf->v;
×
1052
        replaceTupleData(&pDBuf->tuplePos, &pSBuf->tuplePos);
×
1053
        pDBuf->assign = true;
×
1054
      }
1055
      break;
×
1056
    }
1057
    default:
×
1058
      if (pSBuf->assign && (strcmp((char*)&pDBuf->v, (char*)&pSBuf->v) || !pDBuf->assign)) {
×
1059
        pDBuf->v = pSBuf->v;
×
1060
        replaceTupleData(&pDBuf->tuplePos, &pSBuf->tuplePos);
×
1061
        pDBuf->assign = true;
×
1062
      }
1063
      break;
×
1064
  }
1065
  pDResInfo->numOfRes = TMAX(pDResInfo->numOfRes, pSResInfo->numOfRes);
58✔
1066
  pDResInfo->isNullRes &= pSResInfo->isNullRes;
58✔
1067
  return TSDB_CODE_SUCCESS;
58✔
1068
}
1069

1070
int32_t minCombine(SqlFunctionCtx* pDestCtx, SqlFunctionCtx* pSourceCtx) {
11✔
1071
  return minMaxCombine(pDestCtx, pSourceCtx, 1);
11✔
1072
}
1073
int32_t maxCombine(SqlFunctionCtx* pDestCtx, SqlFunctionCtx* pSourceCtx) {
47✔
1074
  return minMaxCombine(pDestCtx, pSourceCtx, 0);
47✔
1075
}
1076

1077
int32_t getStdInfoSize() { return (int32_t)sizeof(SStdRes); }
10,705✔
1078

1079
bool getStdFuncEnv(SFunctionNode* pFunc, SFuncExecEnv* pEnv) {
55,794✔
1080
  pEnv->calcMemSize = sizeof(SStdRes);
55,794✔
1081
  return true;
55,794✔
1082
}
1083

1084
int32_t stdFunctionSetup(SqlFunctionCtx* pCtx, SResultRowEntryInfo* pResultInfo) {
297,354✔
1085
  if (pResultInfo->initialized) {
297,354!
1086
    return TSDB_CODE_SUCCESS;
×
1087
  }
1088
  if (TSDB_CODE_SUCCESS != functionSetup(pCtx, pResultInfo)) {
297,354!
1089
    return TSDB_CODE_FUNC_SETUP_ERROR;
×
1090
  }
1091

1092
  SStdRes* pRes = GET_ROWCELL_INTERBUF(pResultInfo);
297,363✔
1093
  (void)memset(pRes, 0, sizeof(SStdRes));
297,363✔
1094
  return TSDB_CODE_SUCCESS;
297,363✔
1095
}
1096

1097
int32_t stdFunction(SqlFunctionCtx* pCtx) {
303,551✔
1098
  int32_t numOfElem = 0;
303,551✔
1099

1100
  // Only the pre-computing information loaded and actual data does not loaded
1101
  SInputColumnInfoData* pInput = &pCtx->input;
303,551✔
1102
  int32_t               type = pInput->pData[0]->info.type;
303,551✔
1103

1104
  SStdRes* pStdRes = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
303,551✔
1105
  pStdRes->type = type;
303,551✔
1106

1107
  // computing based on the true data block
1108
  SColumnInfoData* pCol = pInput->pData[0];
303,551✔
1109

1110
  int32_t start = pInput->startRowIndex;
303,551✔
1111
  int32_t numOfRows = pInput->numOfRows;
303,551✔
1112

1113
  if (IS_NULL_TYPE(type)) {
303,551✔
1114
    numOfElem = 0;
101✔
1115
    goto _stddev_over;
101✔
1116
  }
1117

1118
  switch (type) {
303,450!
1119
    case TSDB_DATA_TYPE_TINYINT: {
11,135✔
1120
      int8_t* plist = (int8_t*)pCol->pData;
11,135✔
1121
      for (int32_t i = start; i < numOfRows + start; ++i) {
84,892✔
1122
        if (pCol->hasNull && colDataIsNull_f(pCol->nullbitmap, i)) {
73,757✔
1123
          continue;
42,865✔
1124
        }
1125

1126
        numOfElem += 1;
30,892✔
1127
        pStdRes->count += 1;
30,892✔
1128
        pStdRes->isum += plist[i];
30,892✔
1129
        pStdRes->quadraticISum += plist[i] * plist[i];
30,892✔
1130
      }
1131

1132
      break;
11,135✔
1133
    }
1134

1135
    case TSDB_DATA_TYPE_SMALLINT: {
193,212✔
1136
      int16_t* plist = (int16_t*)pCol->pData;
193,212✔
1137
      for (int32_t i = start; i < numOfRows + pInput->startRowIndex; ++i) {
614,704✔
1138
        if (pCol->hasNull && colDataIsNull_f(pCol->nullbitmap, i)) {
421,492✔
1139
          continue;
48,455✔
1140
        }
1141

1142
        numOfElem += 1;
373,037✔
1143
        pStdRes->count += 1;
373,037✔
1144
        pStdRes->isum += plist[i];
373,037✔
1145
        pStdRes->quadraticISum += plist[i] * plist[i];
373,037✔
1146
      }
1147
      break;
193,212✔
1148
    }
1149

1150
    case TSDB_DATA_TYPE_INT: {
18,213✔
1151
      int32_t* plist = (int32_t*)pCol->pData;
18,213✔
1152
      for (int32_t i = start; i < numOfRows + pInput->startRowIndex; ++i) {
158,347✔
1153
        if (pCol->hasNull && colDataIsNull_f(pCol->nullbitmap, i)) {
140,134✔
1154
          continue;
91,169✔
1155
        }
1156

1157
        numOfElem += 1;
48,965✔
1158
        pStdRes->count += 1;
48,965✔
1159
        pStdRes->isum += plist[i];
48,965✔
1160
        pStdRes->quadraticISum += plist[i] * plist[i];
48,965✔
1161
      }
1162

1163
      break;
18,213✔
1164
    }
1165

1166
    case TSDB_DATA_TYPE_BIGINT: {
23,314✔
1167
      int64_t* plist = (int64_t*)pCol->pData;
23,314✔
1168
      for (int32_t i = start; i < numOfRows + pInput->startRowIndex; ++i) {
1,081,493✔
1169
        if (pCol->hasNull && colDataIsNull_f(pCol->nullbitmap, i)) {
1,058,179✔
1170
          continue;
166,820✔
1171
        }
1172

1173
        numOfElem += 1;
891,359✔
1174
        pStdRes->count += 1;
891,359✔
1175
        pStdRes->isum += plist[i];
891,359✔
1176
        pStdRes->quadraticISum += plist[i] * plist[i];
891,359✔
1177
      }
1178
      break;
23,314✔
1179
    }
1180

1181
    case TSDB_DATA_TYPE_UTINYINT: {
1✔
1182
      uint8_t* plist = (uint8_t*)pCol->pData;
1✔
1183
      for (int32_t i = start; i < numOfRows + start; ++i) {
8✔
1184
        if (pCol->hasNull && colDataIsNull_f(pCol->nullbitmap, i)) {
7!
1185
          continue;
4✔
1186
        }
1187

1188
        numOfElem += 1;
3✔
1189
        pStdRes->count += 1;
3✔
1190
        pStdRes->usum += plist[i];
3✔
1191
        pStdRes->quadraticUSum += plist[i] * plist[i];
3✔
1192
      }
1193

1194
      break;
1✔
1195
    }
1196

1197
    case TSDB_DATA_TYPE_USMALLINT: {
×
1198
      uint16_t* plist = (uint16_t*)pCol->pData;
×
1199
      for (int32_t i = start; i < numOfRows + pInput->startRowIndex; ++i) {
×
1200
        if (pCol->hasNull && colDataIsNull_f(pCol->nullbitmap, i)) {
×
1201
          continue;
×
1202
        }
1203

1204
        numOfElem += 1;
×
1205
        pStdRes->count += 1;
×
1206
        pStdRes->usum += plist[i];
×
1207
        pStdRes->quadraticUSum += plist[i] * plist[i];
×
1208
      }
1209
      break;
×
1210
    }
1211

1212
    case TSDB_DATA_TYPE_UINT: {
1✔
1213
      uint32_t* plist = (uint32_t*)pCol->pData;
1✔
1214
      for (int32_t i = start; i < numOfRows + pInput->startRowIndex; ++i) {
6✔
1215
        if (pCol->hasNull && colDataIsNull_f(pCol->nullbitmap, i)) {
5!
1216
          continue;
×
1217
        }
1218

1219
        numOfElem += 1;
5✔
1220
        pStdRes->count += 1;
5✔
1221
        pStdRes->usum += plist[i];
5✔
1222
        pStdRes->quadraticUSum += plist[i] * plist[i];
5✔
1223
      }
1224

1225
      break;
1✔
1226
    }
1227

1228
    case TSDB_DATA_TYPE_UBIGINT: {
×
1229
      uint64_t* plist = (uint64_t*)pCol->pData;
×
1230
      for (int32_t i = start; i < numOfRows + pInput->startRowIndex; ++i) {
×
1231
        if (pCol->hasNull && colDataIsNull_f(pCol->nullbitmap, i)) {
×
1232
          continue;
×
1233
        }
1234

1235
        numOfElem += 1;
×
1236
        pStdRes->count += 1;
×
1237
        pStdRes->usum += plist[i];
×
1238
        pStdRes->quadraticUSum += plist[i] * plist[i];
×
1239
      }
1240
      break;
×
1241
    }
1242

1243
    case TSDB_DATA_TYPE_FLOAT: {
12,283✔
1244
      float* plist = (float*)pCol->pData;
12,283✔
1245
      for (int32_t i = start; i < numOfRows + pInput->startRowIndex; ++i) {
643,914✔
1246
        if (pCol->hasNull && colDataIsNull_f(pCol->nullbitmap, i)) {
631,631✔
1247
          continue;
100,370✔
1248
        }
1249

1250
        numOfElem += 1;
531,261✔
1251
        pStdRes->count += 1;
531,261✔
1252
        pStdRes->dsum += plist[i];
531,261✔
1253
        pStdRes->quadraticDSum += plist[i] * plist[i];
531,261✔
1254
      }
1255
      break;
12,283✔
1256
    }
1257

1258
    case TSDB_DATA_TYPE_DOUBLE: {
45,309✔
1259
      double* plist = (double*)pCol->pData;
45,309✔
1260
      for (int32_t i = start; i < numOfRows + pInput->startRowIndex; ++i) {
1,838,916✔
1261
        if (pCol->hasNull && colDataIsNull_f(pCol->nullbitmap, i)) {
1,793,607✔
1262
          continue;
609,086✔
1263
        }
1264

1265
        numOfElem += 1;
1,184,521✔
1266
        pStdRes->count += 1;
1,184,521✔
1267
        pStdRes->dsum += plist[i];
1,184,521✔
1268
        pStdRes->quadraticDSum += plist[i] * plist[i];
1,184,521✔
1269
      }
1270
      break;
45,309✔
1271
    }
1272

1273
    default:
×
1274
      break;
×
1275
  }
1276

1277
_stddev_over:
303,551✔
1278
  // data in the check operation are all null, not output
1279
  SET_VAL(GET_RES_INFO(pCtx), numOfElem, 1);
303,551✔
1280
  return TSDB_CODE_SUCCESS;
303,551✔
1281
}
1282

1283
static void stdTransferInfo(SStdRes* pInput, SStdRes* pOutput) {
9,174✔
1284
  if (IS_NULL_TYPE(pInput->type)) {
9,174✔
1285
    return;
80✔
1286
  }
1287
  pOutput->type = pInput->type;
9,094✔
1288
  if (IS_SIGNED_NUMERIC_TYPE(pOutput->type)) {
9,094!
1289
    pOutput->quadraticISum += pInput->quadraticISum;
8,995✔
1290
    pOutput->isum += pInput->isum;
8,995✔
1291
  } else if (IS_UNSIGNED_NUMERIC_TYPE(pOutput->type)) {
99!
1292
    pOutput->quadraticUSum += pInput->quadraticUSum;
1✔
1293
    pOutput->usum += pInput->usum;
1✔
1294
  } else {
1295
    pOutput->quadraticDSum += pInput->quadraticDSum;
98✔
1296
    pOutput->dsum += pInput->dsum;
98✔
1297
  }
1298

1299
  pOutput->count += pInput->count;
9,094✔
1300
}
1301

1302
int32_t stdFunctionMerge(SqlFunctionCtx* pCtx) {
9,111✔
1303
  SInputColumnInfoData* pInput = &pCtx->input;
9,111✔
1304
  SColumnInfoData*      pCol = pInput->pData[0];
9,111✔
1305

1306
  if (IS_NULL_TYPE(pCol->info.type)) {
9,111!
1307
    SET_VAL(GET_RES_INFO(pCtx), 0, 1);
×
1308
    return TSDB_CODE_SUCCESS;
×
1309
  }
1310

1311
  if (pCol->info.type != TSDB_DATA_TYPE_BINARY) {
9,111!
1312
    return TSDB_CODE_FUNC_FUNTION_PARA_TYPE;
×
1313
  }
1314

1315
  SStdRes* pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
9,111✔
1316

1317
  for (int32_t i = pInput->startRowIndex; i < pInput->startRowIndex + pInput->numOfRows; ++i) {
18,282✔
1318
    if (colDataIsNull_s(pCol, i)) continue;
18,342!
1319
    char*    data = colDataGetData(pCol, i);
9,171!
1320
    SStdRes* pInputInfo = (SStdRes*)varDataVal(data);
9,171✔
1321
    stdTransferInfo(pInputInfo, pInfo);
9,171✔
1322
  }
1323

1324
  SET_VAL(GET_RES_INFO(pCtx), 1, 1);
9,111✔
1325
  return TSDB_CODE_SUCCESS;
9,111✔
1326
}
1327

1328
#ifdef BUILD_NO_CALL
1329
int32_t stdInvertFunction(SqlFunctionCtx* pCtx) {
1330
  int32_t numOfElem = 0;
1331

1332
  // Only the pre-computing information loaded and actual data does not loaded
1333
  SInputColumnInfoData* pInput = &pCtx->input;
1334
  int32_t               type = pInput->pData[0]->info.type;
1335

1336
  SStdRes* pStdRes = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
1337

1338
  // computing based on the true data block
1339
  SColumnInfoData* pCol = pInput->pData[0];
1340

1341
  int32_t start = pInput->startRowIndex;
1342
  int32_t numOfRows = pInput->numOfRows;
1343

1344
  switch (type) {
1345
    case TSDB_DATA_TYPE_TINYINT: {
1346
      LIST_STDDEV_SUB_N(pStdRes->isum, int8_t);
1347
      break;
1348
    }
1349
    case TSDB_DATA_TYPE_SMALLINT: {
1350
      LIST_STDDEV_SUB_N(pStdRes->isum, int16_t);
1351
      break;
1352
    }
1353
    case TSDB_DATA_TYPE_INT: {
1354
      LIST_STDDEV_SUB_N(pStdRes->isum, int32_t);
1355
      break;
1356
    }
1357
    case TSDB_DATA_TYPE_BIGINT: {
1358
      LIST_STDDEV_SUB_N(pStdRes->isum, int64_t);
1359
      break;
1360
    }
1361
    case TSDB_DATA_TYPE_UTINYINT: {
1362
      LIST_STDDEV_SUB_N(pStdRes->isum, uint8_t);
1363
      break;
1364
    }
1365
    case TSDB_DATA_TYPE_USMALLINT: {
1366
      LIST_STDDEV_SUB_N(pStdRes->isum, uint16_t);
1367
      break;
1368
    }
1369
    case TSDB_DATA_TYPE_UINT: {
1370
      LIST_STDDEV_SUB_N(pStdRes->isum, uint32_t);
1371
      break;
1372
    }
1373
    case TSDB_DATA_TYPE_UBIGINT: {
1374
      LIST_STDDEV_SUB_N(pStdRes->isum, uint64_t);
1375
      break;
1376
    }
1377
    case TSDB_DATA_TYPE_FLOAT: {
1378
      LIST_STDDEV_SUB_N(pStdRes->dsum, float);
1379
      break;
1380
    }
1381
    case TSDB_DATA_TYPE_DOUBLE: {
1382
      LIST_STDDEV_SUB_N(pStdRes->dsum, double);
1383
      break;
1384
    }
1385
    default:
1386
      break;
1387
  }
1388

1389
  // data in the check operation are all null, not output
1390
  SET_VAL(GET_RES_INFO(pCtx), numOfElem, 1);
1391
  return TSDB_CODE_SUCCESS;
1392
}
1393
#endif
1394

1395
int32_t stddevFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
262,810✔
1396
  SInputColumnInfoData* pInput = &pCtx->input;
262,810✔
1397
  SStdRes*              pStddevRes = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
262,810✔
1398
  int32_t               type = pStddevRes->type;
262,810✔
1399
  double                avg;
1400

1401
  if (pStddevRes->count == 0) {
262,810✔
1402
    GET_RES_INFO(pCtx)->numOfRes = 0;
58,485✔
1403
    return functionFinalize(pCtx, pBlock);
58,485✔
1404
  }
1405

1406
  if (IS_SIGNED_NUMERIC_TYPE(type)) {
204,325!
1407
    avg = pStddevRes->isum / ((double)pStddevRes->count);
177,174✔
1408
    pStddevRes->result = sqrt(fabs(pStddevRes->quadraticISum / ((double)pStddevRes->count) - avg * avg));
177,174✔
1409
  } else if (IS_UNSIGNED_NUMERIC_TYPE(type)) {
27,151!
1410
    avg = pStddevRes->usum / ((double)pStddevRes->count);
2✔
1411
    pStddevRes->result = sqrt(fabs(pStddevRes->quadraticUSum / ((double)pStddevRes->count) - avg * avg));
2✔
1412
  } else {
1413
    avg = pStddevRes->dsum / ((double)pStddevRes->count);
27,149✔
1414
    pStddevRes->result = sqrt(fabs(pStddevRes->quadraticDSum / ((double)pStddevRes->count) - avg * avg));
27,149✔
1415
  }
1416

1417
  // check for overflow
1418
  if (isinf(pStddevRes->result) || isnan(pStddevRes->result)) {
204,325!
1419
    GET_RES_INFO(pCtx)->numOfRes = 0;
×
1420
  }
1421

1422
  return functionFinalize(pCtx, pBlock);
204,325✔
1423
}
1424

1425
int32_t stdvarFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
×
1426
  SInputColumnInfoData* pInput = &pCtx->input;
×
1427
  SStdRes*              pStdvarRes = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
×
1428
  int32_t               type = pStdvarRes->type;
×
1429
  double                avg;
1430

1431
  if (pStdvarRes->count == 0) {
×
1432
    GET_RES_INFO(pCtx)->numOfRes = 0;
×
1433
    return functionFinalize(pCtx, pBlock);
×
1434
  }
1435

1436
  if (IS_SIGNED_NUMERIC_TYPE(type)) {
×
1437
    avg = pStdvarRes->isum / ((double)pStdvarRes->count);
×
1438
    pStdvarRes->result = fabs(pStdvarRes->quadraticISum / ((double)pStdvarRes->count) - avg * avg);
×
1439
  } else if (IS_UNSIGNED_NUMERIC_TYPE(type)) {
×
1440
    avg = pStdvarRes->usum / ((double)pStdvarRes->count);
×
1441
    pStdvarRes->result = fabs(pStdvarRes->quadraticUSum / ((double)pStdvarRes->count) - avg * avg);
×
1442
  } else {
1443
    avg = pStdvarRes->dsum / ((double)pStdvarRes->count);
×
1444
    pStdvarRes->result = fabs(pStdvarRes->quadraticDSum / ((double)pStdvarRes->count) - avg * avg);
×
1445
  }
1446

1447
  // check for overflow
1448
  if (isinf(pStdvarRes->result) || isnan(pStdvarRes->result)) {
×
1449
    GET_RES_INFO(pCtx)->numOfRes = 0;
×
1450
  }
1451

1452
  return functionFinalize(pCtx, pBlock);
×
1453
}
1454

1455
int32_t stdPartialFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
9,077✔
1456
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
9,077✔
1457
  SStdRes*             pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
9,077✔
1458
  int32_t              resultBytes = getStdInfoSize();
9,077✔
1459
  char*                res = taosMemoryCalloc(resultBytes + VARSTR_HEADER_SIZE, sizeof(char));
9,077!
1460

1461
  if (NULL == res) {
9,078!
1462
    return terrno;
×
1463
  }
1464
  (void)memcpy(varDataVal(res), pInfo, resultBytes);
9,078✔
1465
  varDataSetLen(res, resultBytes);
9,078✔
1466

1467
  int32_t          slotId = pCtx->pExpr->base.resSchema.slotId;
9,078✔
1468
  SColumnInfoData* pCol = taosArrayGet(pBlock->pDataBlock, slotId);
9,078✔
1469
  if (NULL == pCol) {
9,078!
1470
    taosMemoryFree(res);
×
1471
    return TSDB_CODE_OUT_OF_RANGE;
×
1472
  }
1473

1474
  int32_t code = colDataSetVal(pCol, pBlock->info.rows, res, false);
9,078✔
1475

1476
  taosMemoryFree(res);
9,078!
1477
  return code;
9,078✔
1478
}
1479

1480
int32_t stdCombine(SqlFunctionCtx* pDestCtx, SqlFunctionCtx* pSourceCtx) {
3✔
1481
  SResultRowEntryInfo* pDResInfo = GET_RES_INFO(pDestCtx);
3✔
1482
  SStdRes*             pDBuf = GET_ROWCELL_INTERBUF(pDResInfo);
3✔
1483

1484
  SResultRowEntryInfo* pSResInfo = GET_RES_INFO(pSourceCtx);
3✔
1485
  SStdRes*             pSBuf = GET_ROWCELL_INTERBUF(pSResInfo);
3✔
1486
  int16_t              type = pDBuf->type == TSDB_DATA_TYPE_NULL ? pSBuf->type : pDBuf->type;
3!
1487

1488
  stdTransferInfo(pSBuf, pDBuf);
3✔
1489

1490
  pDResInfo->numOfRes = TMAX(pDResInfo->numOfRes, pSResInfo->numOfRes);
3✔
1491
  pDResInfo->isNullRes &= pSResInfo->isNullRes;
3✔
1492
  return TSDB_CODE_SUCCESS;
3✔
1493
}
1494

1495
bool getLeastSQRFuncEnv(SFunctionNode* pFunc, SFuncExecEnv* pEnv) {
8,081✔
1496
  pEnv->calcMemSize = sizeof(SLeastSQRInfo);
8,081✔
1497
  return true;
8,081✔
1498
}
1499

1500
int32_t leastSQRFunctionSetup(SqlFunctionCtx* pCtx, SResultRowEntryInfo* pResultInfo) {
45,496✔
1501
  if (pResultInfo->initialized) {
45,496!
1502
    return TSDB_CODE_SUCCESS;
×
1503
  }
1504
  if (TSDB_CODE_SUCCESS != functionSetup(pCtx, pResultInfo)) {
45,496!
1505
    return TSDB_CODE_FUNC_SETUP_ERROR;
×
1506
  }
1507

1508
  SLeastSQRInfo* pInfo = GET_ROWCELL_INTERBUF(pResultInfo);
45,498✔
1509

1510
  GET_TYPED_DATA(pInfo->startVal, double, pCtx->param[1].param.nType, &pCtx->param[1].param.i);
45,498!
1511
  GET_TYPED_DATA(pInfo->stepVal, double, pCtx->param[2].param.nType, &pCtx->param[2].param.i);
45,498!
1512
  return TSDB_CODE_SUCCESS;
45,498✔
1513
}
1514

1515
int32_t leastSQRFunction(SqlFunctionCtx* pCtx) {
48,475✔
1516
  int32_t numOfElem = 0;
48,475✔
1517

1518
  SInputColumnInfoData* pInput = &pCtx->input;
48,475✔
1519
  int32_t               type = pInput->pData[0]->info.type;
48,475✔
1520

1521
  SLeastSQRInfo* pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
48,475✔
1522

1523
  SColumnInfoData* pCol = pInput->pData[0];
48,475✔
1524

1525
  double(*param)[3] = pInfo->matrix;
48,475✔
1526
  double x = pInfo->startVal;
48,475✔
1527

1528
  int32_t start = pInput->startRowIndex;
48,475✔
1529
  int32_t numOfRows = pInput->numOfRows;
48,475✔
1530

1531
  switch (type) {
48,475!
1532
    case TSDB_DATA_TYPE_TINYINT: {
4,280✔
1533
      int8_t* plist = (int8_t*)pCol->pData;
4,280✔
1534
      for (int32_t i = start; i < numOfRows + pInput->startRowIndex; ++i) {
8,932✔
1535
        if (pCol->hasNull && colDataIsNull_f(pCol->nullbitmap, i)) {
4,652✔
1536
          continue;
2,636✔
1537
        }
1538
        numOfElem++;
2,016✔
1539
        LEASTSQR_CAL(param, x, plist, i, pInfo->stepVal);
2,016✔
1540
      }
1541
      break;
4,280✔
1542
    }
1543
    case TSDB_DATA_TYPE_SMALLINT: {
4,288✔
1544
      int16_t* plist = (int16_t*)pCol->pData;
4,288✔
1545
      for (int32_t i = start; i < numOfRows + pInput->startRowIndex; ++i) {
9,740✔
1546
        if (pCol->hasNull && colDataIsNull_f(pCol->nullbitmap, i)) {
5,452✔
1547
          continue;
3,236✔
1548
        }
1549

1550
        numOfElem++;
2,216✔
1551
        LEASTSQR_CAL(param, x, plist, i, pInfo->stepVal);
2,216✔
1552
      }
1553
      break;
4,288✔
1554
    }
1555

1556
    case TSDB_DATA_TYPE_INT: {
9,259✔
1557
      int32_t* plist = (int32_t*)pCol->pData;
9,259✔
1558
      for (int32_t i = start; i < numOfRows + pInput->startRowIndex; ++i) {
172,849✔
1559
        if (pCol->hasNull && colDataIsNull_f(pCol->nullbitmap, i)) {
163,590✔
1560
          continue;
149,344✔
1561
        }
1562

1563
        numOfElem++;
14,246✔
1564
        LEASTSQR_CAL(param, x, plist, i, pInfo->stepVal);
14,246✔
1565
      }
1566
      break;
9,259✔
1567
    }
1568

1569
    case TSDB_DATA_TYPE_BIGINT: {
16,167✔
1570
      int64_t* plist = (int64_t*)pCol->pData;
16,167✔
1571
      for (int32_t i = start; i < numOfRows + pInput->startRowIndex; ++i) {
858,667✔
1572
        if (pCol->hasNull && colDataIsNull_f(pCol->nullbitmap, i)) {
842,500✔
1573
          continue;
285,223✔
1574
        }
1575

1576
        numOfElem++;
557,277✔
1577
        LEASTSQR_CAL(param, x, plist, i, pInfo->stepVal);
557,277✔
1578
      }
1579
      break;
16,167✔
1580
    }
1581

1582
    case TSDB_DATA_TYPE_UTINYINT: {
78✔
1583
      uint8_t* plist = (uint8_t*)pCol->pData;
78✔
1584
      for (int32_t i = start; i < numOfRows + pInput->startRowIndex; ++i) {
330✔
1585
        if (pCol->hasNull && colDataIsNull_f(pCol->nullbitmap, i)) {
252!
1586
          continue;
66✔
1587
        }
1588
        numOfElem++;
186✔
1589
        LEASTSQR_CAL(param, x, plist, i, pInfo->stepVal);
186✔
1590
      }
1591
      break;
78✔
1592
    }
1593
    case TSDB_DATA_TYPE_USMALLINT: {
78✔
1594
      uint16_t* plist = (uint16_t*)pCol->pData;
78✔
1595
      for (int32_t i = start; i < numOfRows + pInput->startRowIndex; ++i) {
330✔
1596
        if (pCol->hasNull && colDataIsNull_f(pCol->nullbitmap, i)) {
252!
1597
          continue;
60✔
1598
        }
1599

1600
        numOfElem++;
192✔
1601
        LEASTSQR_CAL(param, x, plist, i, pInfo->stepVal);
192✔
1602
      }
1603
      break;
78✔
1604
    }
1605

1606
    case TSDB_DATA_TYPE_UINT: {
78✔
1607
      uint32_t* plist = (uint32_t*)pCol->pData;
78✔
1608
      for (int32_t i = start; i < numOfRows + pInput->startRowIndex; ++i) {
330✔
1609
        if (pCol->hasNull && colDataIsNull_f(pCol->nullbitmap, i)) {
252!
1610
          continue;
60✔
1611
        }
1612

1613
        numOfElem++;
192✔
1614
        LEASTSQR_CAL(param, x, plist, i, pInfo->stepVal);
192✔
1615
      }
1616
      break;
78✔
1617
    }
1618

1619
    case TSDB_DATA_TYPE_UBIGINT: {
78✔
1620
      uint64_t* plist = (uint64_t*)pCol->pData;
78✔
1621
      for (int32_t i = start; i < numOfRows + pInput->startRowIndex; ++i) {
330✔
1622
        if (pCol->hasNull && colDataIsNull_f(pCol->nullbitmap, i)) {
252!
1623
          continue;
60✔
1624
        }
1625

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

1632
    case TSDB_DATA_TYPE_FLOAT: {
8,313✔
1633
      float* plist = (float*)pCol->pData;
8,313✔
1634
      for (int32_t i = start; i < numOfRows + pInput->startRowIndex; ++i) {
160,188✔
1635
        if (pCol->hasNull && colDataIsNull_f(pCol->nullbitmap, i)) {
151,875✔
1636
          continue;
148,859✔
1637
        }
1638

1639
        numOfElem++;
3,016✔
1640
        LEASTSQR_CAL(param, x, plist, i, pInfo->stepVal);
3,016✔
1641
      }
1642
      break;
8,313✔
1643
    }
1644

1645
    case TSDB_DATA_TYPE_DOUBLE: {
5,854✔
1646
      double* plist = (double*)pCol->pData;
5,854✔
1647
      for (int32_t i = start; i < numOfRows + pInput->startRowIndex; ++i) {
15,270✔
1648
        if (pCol->hasNull && colDataIsNull_f(pCol->nullbitmap, i)) {
9,416✔
1649
          continue;
3,036✔
1650
        }
1651

1652
        numOfElem++;
6,380✔
1653
        LEASTSQR_CAL(param, x, plist, i, pInfo->stepVal);
6,380✔
1654
      }
1655
      break;
5,854✔
1656
    }
1657
    case TSDB_DATA_TYPE_NULL: {
×
1658
      GET_RES_INFO(pCtx)->isNullRes = 1;
×
1659
      numOfElem = 1;
×
1660
      break;
×
1661
    }
1662

1663
    default:
2✔
1664
      break;
2✔
1665
  }
1666

1667
  pInfo->startVal = x;
48,475✔
1668
  pInfo->num += numOfElem;
48,475✔
1669

1670
  SET_VAL(GET_RES_INFO(pCtx), numOfElem, 1);
48,475✔
1671

1672
  return TSDB_CODE_SUCCESS;
48,475✔
1673
}
1674

1675
int32_t leastSQRFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
45,500✔
1676
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
45,500✔
1677
  SLeastSQRInfo*       pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
45,500✔
1678
  int32_t              slotId = pCtx->pExpr->base.resSchema.slotId;
45,500✔
1679
  SColumnInfoData*     pCol = taosArrayGet(pBlock->pDataBlock, slotId);
45,500✔
1680

1681
  if (NULL == pCol) {
45,500!
1682
    return TSDB_CODE_OUT_OF_RANGE;
×
1683
  }
1684
  int32_t currentRow = pBlock->info.rows;
45,500✔
1685

1686
  if (0 == pInfo->num) {
45,500✔
1687
    colDataSetNULL(pCol, currentRow);
27,259!
1688
    return TSDB_CODE_SUCCESS;
27,259✔
1689
  }
1690

1691
  double(*param)[3] = pInfo->matrix;
18,241✔
1692

1693
  param[1][1] = (double)pInfo->num;
18,241✔
1694
  param[1][0] = param[0][1];
18,241✔
1695

1696
  double param00 = param[0][0] - param[1][0] * (param[0][1] / param[1][1]);
18,241✔
1697
  double param02 = param[0][2] - param[1][2] * (param[0][1] / param[1][1]);
18,241✔
1698

1699
  if (0 == param00) {
18,241✔
1700
    colDataSetNULL(pCol, currentRow);
13,851!
1701
    return TSDB_CODE_SUCCESS;
13,851✔
1702
  }
1703

1704
  // param[0][1] = 0;
1705
  double param12 = param[1][2] - param02 * (param[1][0] / param00);
4,390✔
1706
  // param[1][0] = 0;
1707
  param02 /= param00;
4,390✔
1708

1709
  param12 /= param[1][1];
4,390✔
1710

1711
  char buf[LEASTSQUARES_BUFF_LENGTH] = {0};
4,390✔
1712
  char slopBuf[64] = {0};
4,390✔
1713
  char interceptBuf[64] = {0};
4,390✔
1714
  int  n = tsnprintf(slopBuf, 64, "%.6lf", param02);
4,390✔
1715
  if (n > LEASTSQUARES_DOUBLE_ITEM_LENGTH) {
4,392✔
1716
    (void)snprintf(slopBuf, 64, "%." DOUBLE_PRECISION_DIGITS, param02);
46✔
1717
  }
1718
  n = tsnprintf(interceptBuf, 64, "%.6lf", param12);
4,392✔
1719
  if (n > LEASTSQUARES_DOUBLE_ITEM_LENGTH) {
4,392✔
1720
    (void)snprintf(interceptBuf, 64, "%." DOUBLE_PRECISION_DIGITS, param12);
3,755✔
1721
  }
1722
  size_t len =
4,392✔
1723
      snprintf(varDataVal(buf), sizeof(buf) - VARSTR_HEADER_SIZE, "{slop:%s, intercept:%s}", slopBuf, interceptBuf);
4,392✔
1724
  varDataSetLen(buf, len);
4,392✔
1725

1726
  int32_t code = colDataSetVal(pCol, currentRow, buf, pResInfo->isNullRes);
4,392✔
1727

1728
  return code;
4,394✔
1729
}
1730

1731
int32_t leastSQRCombine(SqlFunctionCtx* pDestCtx, SqlFunctionCtx* pSourceCtx) {
×
1732
  SResultRowEntryInfo* pDResInfo = GET_RES_INFO(pDestCtx);
×
1733
  SLeastSQRInfo*       pDBuf = GET_ROWCELL_INTERBUF(pDResInfo);
×
1734
  int32_t              type = pDestCtx->input.pData[0]->info.type;
×
1735
  double(*pDparam)[3] = pDBuf->matrix;
×
1736

1737
  SResultRowEntryInfo* pSResInfo = GET_RES_INFO(pSourceCtx);
×
1738
  SLeastSQRInfo*       pSBuf = GET_ROWCELL_INTERBUF(pSResInfo);
×
1739
  double(*pSparam)[3] = pSBuf->matrix;
×
1740
  for (int32_t i = 0; i < pSBuf->num; i++) {
×
1741
    pDparam[0][0] += pDBuf->startVal * pDBuf->startVal;
×
1742
    pDparam[0][1] += pDBuf->startVal;
×
1743
    pDBuf->startVal += pDBuf->stepVal;
×
1744
  }
1745
  pDparam[0][2] += pSparam[0][2] + pDBuf->num * pDBuf->stepVal * pSparam[1][2];
×
1746
  pDparam[1][2] += pSparam[1][2];
×
1747
  pDBuf->num += pSBuf->num;
×
1748
  pDResInfo->numOfRes = TMAX(pDResInfo->numOfRes, pSResInfo->numOfRes);
×
1749
  pDResInfo->isNullRes &= pSResInfo->isNullRes;
×
1750
  return TSDB_CODE_SUCCESS;
×
1751
}
1752

1753
bool getPercentileFuncEnv(SFunctionNode* pFunc, SFuncExecEnv* pEnv) {
584✔
1754
  pEnv->calcMemSize = sizeof(SPercentileInfo);
584✔
1755
  return true;
584✔
1756
}
1757

1758
int32_t percentileFunctionSetup(SqlFunctionCtx* pCtx, SResultRowEntryInfo* pResultInfo) {
6,200✔
1759
  if (pResultInfo->initialized) {
6,200!
1760
    return TSDB_CODE_SUCCESS;
×
1761
  }
1762
  if (TSDB_CODE_SUCCESS != functionSetup(pCtx, pResultInfo)) {
6,200!
1763
    return TSDB_CODE_FUNC_SETUP_ERROR;
×
1764
  }
1765

1766
  // in the first round, get the min-max value of all involved data
1767
  SPercentileInfo* pInfo = GET_ROWCELL_INTERBUF(pResultInfo);
6,200✔
1768
  SET_DOUBLE_VAL(&pInfo->minval, DBL_MAX);
6,200✔
1769
  SET_DOUBLE_VAL(&pInfo->maxval, -DBL_MAX);
6,200✔
1770
  pInfo->numOfElems = 0;
6,200✔
1771

1772
  return TSDB_CODE_SUCCESS;
6,200✔
1773
}
1774

1775
void percentileFunctionCleanupExt(SqlFunctionCtx* pCtx) {
×
1776
  if (pCtx == NULL || GET_RES_INFO(pCtx) == NULL || GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx)) == NULL) {
×
1777
    return;
×
1778
  }
1779
  SPercentileInfo* pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
×
1780
  if (pInfo->pMemBucket != NULL) {
×
1781
    tMemBucketDestroy(&(pInfo->pMemBucket));
×
1782
    pInfo->pMemBucket = NULL;
×
1783
  }
1784
}
1785

1786
int32_t percentileFunction(SqlFunctionCtx* pCtx) {
14,350✔
1787
  int32_t              code = TSDB_CODE_SUCCESS;
14,350✔
1788
  int32_t              numOfElems = 0;
14,350✔
1789
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
14,350✔
1790

1791
  SInputColumnInfoData* pInput = &pCtx->input;
14,350✔
1792
  SColumnDataAgg*       pAgg = pInput->pColumnDataAgg[0];
14,350✔
1793

1794
  SColumnInfoData* pCol = pInput->pData[0];
14,350✔
1795
  int32_t          type = pCol->info.type;
14,350✔
1796

1797
  SPercentileInfo* pInfo = GET_ROWCELL_INTERBUF(pResInfo);
14,350✔
1798
  if (pCtx->scanFlag == MAIN_SCAN && pInfo->stage == 0) {
14,350✔
1799
    pInfo->stage += 1;
6,200✔
1800

1801
    // all data are null, set it completed
1802
    if (pInfo->numOfElems == 0) {
6,200✔
1803
      pResInfo->complete = true;
1,770✔
1804
      return TSDB_CODE_SUCCESS;
1,770✔
1805
    } else {
1806
      code = tMemBucketCreate(pCol->info.bytes, type, pInfo->minval, pInfo->maxval, pCtx->hasWindowOrGroup,
4,430✔
1807
                              &pInfo->pMemBucket, pInfo->numOfElems);
4,430✔
1808
      if (TSDB_CODE_SUCCESS != code) {
4,430!
1809
        return code;
×
1810
      }
1811
    }
1812
  }
1813

1814
  // the first stage, only acquire the min/max value
1815
  if (pInfo->stage == 0) {
12,580✔
1816
    if (pCtx->input.colDataSMAIsSet) {
7,190!
1817
      double tmin = 0.0, tmax = 0.0;
×
1818
      if (IS_SIGNED_NUMERIC_TYPE(type)) {
×
1819
        tmin = (double)GET_INT64_VAL(&pAgg->min);
×
1820
        tmax = (double)GET_INT64_VAL(&pAgg->max);
×
1821
      } else if (IS_FLOAT_TYPE(type)) {
×
1822
        tmin = GET_DOUBLE_VAL(&pAgg->min);
×
1823
        tmax = GET_DOUBLE_VAL(&pAgg->max);
×
1824
      } else if (IS_UNSIGNED_NUMERIC_TYPE(type)) {
×
1825
        tmin = (double)GET_UINT64_VAL(&pAgg->min);
×
1826
        tmax = (double)GET_UINT64_VAL(&pAgg->max);
×
1827
      }
1828

1829
      if (GET_DOUBLE_VAL(&pInfo->minval) > tmin) {
×
1830
        SET_DOUBLE_VAL(&pInfo->minval, tmin);
×
1831
      }
1832

1833
      if (GET_DOUBLE_VAL(&pInfo->maxval) < tmax) {
×
1834
        SET_DOUBLE_VAL(&pInfo->maxval, tmax);
×
1835
      }
1836

1837
      pInfo->numOfElems += (pInput->numOfRows - pAgg->numOfNull);
×
1838
    } else {
1839
      // check the valid data one by one
1840
      int32_t start = pInput->startRowIndex;
7,190✔
1841
      for (int32_t i = start; i < pInput->numOfRows + start; ++i) {
318,828✔
1842
        if (colDataIsNull_f(pCol->nullbitmap, i)) {
311,638✔
1843
          continue;
1,800✔
1844
        }
1845

1846
        char* data = colDataGetData(pCol, i);
309,838!
1847

1848
        double v = 0;
309,838✔
1849
        GET_TYPED_DATA(v, double, type, data);
309,838!
1850
        if (v < GET_DOUBLE_VAL(&pInfo->minval)) {
309,838✔
1851
          SET_DOUBLE_VAL(&pInfo->minval, v);
4,592✔
1852
        }
1853

1854
        if (v > GET_DOUBLE_VAL(&pInfo->maxval)) {
309,838✔
1855
          SET_DOUBLE_VAL(&pInfo->maxval, v);
249,198✔
1856
        }
1857

1858
        pInfo->numOfElems += 1;
309,838✔
1859
      }
1860
    }
1861
  } else {
1862
    // the second stage, calculate the true percentile value
1863
    int32_t start = pInput->startRowIndex;
5,390✔
1864
    for (int32_t i = start; i < pInput->numOfRows + start; ++i) {
315,228✔
1865
      if (colDataIsNull_f(pCol->nullbitmap, i)) {
309,838!
1866
        continue;
×
1867
      }
1868

1869
      char* data = colDataGetData(pCol, i);
309,838!
1870
      numOfElems += 1;
309,838✔
1871
      code = tMemBucketPut(pInfo->pMemBucket, data, 1);
309,838✔
1872
      if (code != TSDB_CODE_SUCCESS) {
309,838!
1873
        tMemBucketDestroy(&(pInfo->pMemBucket));
×
1874
        return code;
×
1875
      }
1876
    }
1877

1878
    SET_VAL(pResInfo, numOfElems, 1);
5,390!
1879
  }
1880

1881
  pCtx->needCleanup = true;
12,580✔
1882
  return TSDB_CODE_SUCCESS;
12,580✔
1883
}
1884

1885
int32_t percentileFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
6,200✔
1886
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
6,200✔
1887
  SPercentileInfo*     ppInfo = (SPercentileInfo*)GET_ROWCELL_INTERBUF(pResInfo);
6,200✔
1888

1889
  int32_t code = 0;
6,200✔
1890
  double  v = 0;
6,200✔
1891

1892
  tMemBucket** pMemBucket = &ppInfo->pMemBucket;
6,200✔
1893
  if ((*pMemBucket) != NULL && (*pMemBucket)->total > 0) {  // check for null
6,200!
1894
    if (pCtx->numOfParams > 2) {
4,430✔
1895
      char buf[3200] = {0};
18✔
1896
      // max length of double num is 317, e.g. use %.6lf to print -1.0e+308, consider the comma and bracket, 3200 is
1897
      // enough.
1898
      size_t len = 1;
18✔
1899

1900
      varDataVal(buf)[0] = '[';
18✔
1901
      for (int32_t i = 1; i < pCtx->numOfParams; ++i) {
198✔
1902
        SVariant* pVal = &pCtx->param[i].param;
180✔
1903

1904
        GET_TYPED_DATA(v, double, pVal->nType, &pVal->i);
180!
1905

1906
        code = getPercentile((*pMemBucket), v, &ppInfo->result);
180✔
1907
        if (code != TSDB_CODE_SUCCESS) {
180!
1908
          goto _fin_error;
×
1909
        }
1910

1911
        if (i == pCtx->numOfParams - 1) {
180✔
1912
          len += tsnprintf(varDataVal(buf) + len, sizeof(buf) - VARSTR_HEADER_SIZE - len, "%.6lf]", ppInfo->result);
18✔
1913
        } else {
1914
          len += tsnprintf(varDataVal(buf) + len, sizeof(buf) - VARSTR_HEADER_SIZE - len, "%.6lf, ", ppInfo->result);
162✔
1915
        }
1916
      }
1917

1918
      int32_t          slotId = pCtx->pExpr->base.resSchema.slotId;
18✔
1919
      SColumnInfoData* pCol = taosArrayGet(pBlock->pDataBlock, slotId);
18✔
1920
      if (NULL == pCol) {
18!
1921
        code = terrno;
×
1922
        goto _fin_error;
×
1923
      }
1924

1925
      varDataSetLen(buf, len);
18✔
1926
      code = colDataSetVal(pCol, pBlock->info.rows, buf, false);
18✔
1927
      if (code != TSDB_CODE_SUCCESS) {
18!
1928
        goto _fin_error;
×
1929
      }
1930

1931
      tMemBucketDestroy(pMemBucket);
18✔
1932
      return TSDB_CODE_SUCCESS;
18✔
1933
    } else {
1934
      SVariant* pVal = &pCtx->param[1].param;
4,412✔
1935

1936
      GET_TYPED_DATA(v, double, pVal->nType, &pVal->i);
4,412!
1937

1938
      code = getPercentile((*pMemBucket), v, &ppInfo->result);
4,412✔
1939
      if (code != TSDB_CODE_SUCCESS) {
4,412!
1940
        goto _fin_error;
×
1941
      }
1942

1943
      tMemBucketDestroy(pMemBucket);
4,412✔
1944
      return functionFinalize(pCtx, pBlock);
4,412✔
1945
    }
1946
  } else {
1947
    return functionFinalize(pCtx, pBlock);
1,770✔
1948
  }
1949

1950
_fin_error:
×
1951

1952
  tMemBucketDestroy(pMemBucket);
×
1953
  return code;
×
1954
}
1955

1956
bool getApercentileFuncEnv(SFunctionNode* pFunc, SFuncExecEnv* pEnv) {
61,917✔
1957
  int32_t bytesHist =
61,917✔
1958
      (int32_t)(sizeof(SAPercentileInfo) + sizeof(SHistogramInfo) + sizeof(SHistBin) * (MAX_HISTOGRAM_BIN + 1));
1959
  int32_t bytesDigest = (int32_t)(sizeof(SAPercentileInfo) + TDIGEST_SIZE(COMPRESSION));
61,917✔
1960
  pEnv->calcMemSize = TMAX(bytesHist, bytesDigest);
61,917✔
1961
  return true;
61,917✔
1962
}
1963

1964
int32_t getApercentileMaxSize() {
10,001✔
1965
  int32_t bytesHist =
10,001✔
1966
      (int32_t)(sizeof(SAPercentileInfo) + sizeof(SHistogramInfo) + sizeof(SHistBin) * (MAX_HISTOGRAM_BIN + 1));
1967
  int32_t bytesDigest = (int32_t)(sizeof(SAPercentileInfo) + TDIGEST_SIZE(COMPRESSION));
10,001✔
1968
  return TMAX(bytesHist, bytesDigest);
10,001✔
1969
}
1970

1971
static int8_t getApercentileAlgo(char* algoStr) {
22,315✔
1972
  int8_t algoType;
1973
  if (strcasecmp(algoStr, "default") == 0) {
22,315✔
1974
    algoType = APERCT_ALGO_DEFAULT;
11,149✔
1975
  } else if (strcasecmp(algoStr, "t-digest") == 0) {
11,166✔
1976
    algoType = APERCT_ALGO_TDIGEST;
11,163✔
1977
  } else {
1978
    algoType = APERCT_ALGO_UNKNOWN;
3✔
1979
  }
1980

1981
  return algoType;
22,315✔
1982
}
1983

1984
static void buildHistogramInfo(SAPercentileInfo* pInfo) {
834,483✔
1985
  pInfo->pHisto = (SHistogramInfo*)((char*)pInfo + sizeof(SAPercentileInfo));
834,483✔
1986
  pInfo->pHisto->elems = (SHistBin*)((char*)pInfo->pHisto + sizeof(SHistogramInfo));
834,483✔
1987
}
834,483✔
1988

1989
static void buildTDigestInfo(SAPercentileInfo* pInfo) {
22,424✔
1990
  pInfo->pTDigest = (TDigest*)((char*)pInfo + sizeof(SAPercentileInfo));
22,424✔
1991
}
22,424✔
1992

1993
int32_t apercentileFunctionSetup(SqlFunctionCtx* pCtx, SResultRowEntryInfo* pResultInfo) {
290,387✔
1994
  if (pResultInfo->initialized) {
290,387!
1995
    return TSDB_CODE_SUCCESS;
×
1996
  }
1997
  if (TSDB_CODE_SUCCESS != functionSetup(pCtx, pResultInfo)) {
290,387!
1998
    return TSDB_CODE_FUNC_SETUP_ERROR;
×
1999
  }
2000

2001
  SAPercentileInfo* pInfo = GET_ROWCELL_INTERBUF(pResultInfo);
290,420✔
2002

2003
  SVariant* pVal = &pCtx->param[1].param;
290,420✔
2004
  pInfo->percent = 0;
290,420✔
2005
  GET_TYPED_DATA(pInfo->percent, double, pVal->nType, &pVal->i);
290,420!
2006

2007
  if (pCtx->numOfParams == 2) {
290,420✔
2008
    pInfo->algo = APERCT_ALGO_DEFAULT;
268,108✔
2009
  } else if (pCtx->numOfParams == 3) {
22,312!
2010
    pInfo->algo = getApercentileAlgo(varDataVal(pCtx->param[2].param.pz));
22,315✔
2011
    if (pInfo->algo == APERCT_ALGO_UNKNOWN) {
22,309!
2012
      return TSDB_CODE_FUNC_FUNTION_PARA_VALUE;
×
2013
    }
2014
  }
2015

2016
  char* tmp = (char*)pInfo + sizeof(SAPercentileInfo);
290,414✔
2017
  if (pInfo->algo == APERCT_ALGO_TDIGEST) {
290,414✔
2018
    pInfo->pTDigest = tdigestNewFrom(tmp, COMPRESSION);
11,163✔
2019
  } else {
2020
    buildHistogramInfo(pInfo);
279,251✔
2021
    pInfo->pHisto = tHistogramCreateFrom(tmp, MAX_HISTOGRAM_BIN);
279,257✔
2022
    qDebug("%s set up histogram, numOfElems:%" PRId64 ", numOfEntry:%d, pHisto:%p, elems:%p", __FUNCTION__,
279,252✔
2023
           pInfo->pHisto->numOfElems, pInfo->pHisto->numOfEntries, pInfo->pHisto, pInfo->pHisto->elems);
2024
  }
2025

2026
  return TSDB_CODE_SUCCESS;
290,418✔
2027
}
2028

2029
int32_t apercentileFunction(SqlFunctionCtx* pCtx) {
295,564✔
2030
  int32_t               numOfElems = 0;
295,564✔
2031
  SResultRowEntryInfo*  pResInfo = GET_RES_INFO(pCtx);
295,564✔
2032
  SInputColumnInfoData* pInput = &pCtx->input;
295,564✔
2033

2034
  SColumnInfoData* pCol = pInput->pData[0];
295,564✔
2035
  int32_t          type = pCol->info.type;
295,564✔
2036

2037
  SAPercentileInfo* pInfo = GET_ROWCELL_INTERBUF(pResInfo);
295,564✔
2038

2039
  int32_t start = pInput->startRowIndex;
295,564✔
2040
  if (pInfo->algo == APERCT_ALGO_TDIGEST) {
295,564✔
2041
    buildTDigestInfo(pInfo);
11,166✔
2042
    tdigestAutoFill(pInfo->pTDigest, COMPRESSION);
11,166✔
2043
    for (int32_t i = start; i < pInput->numOfRows + start; ++i) {
582,225✔
2044
      if (colDataIsNull_f(pCol->nullbitmap, i)) {
571,046✔
2045
        continue;
289,484✔
2046
      }
2047
      numOfElems += 1;
281,562✔
2048
      char* data = colDataGetData(pCol, i);
281,562!
2049

2050
      double  v = 0;  // value
281,562✔
2051
      int64_t w = 1;  // weigth
281,562✔
2052
      GET_TYPED_DATA(v, double, type, data);
281,562✔
2053
      int32_t code = tdigestAdd(pInfo->pTDigest, v, w);
281,562✔
2054
      if (code != TSDB_CODE_SUCCESS) {
281,577!
2055
        return code;
×
2056
      }
2057
    }
2058
  } else {
2059
    // might be a race condition here that pHisto can be overwritten or setup function
2060
    // has not been called, need to relink the buffer pHisto points to.
2061
    buildHistogramInfo(pInfo);
284,398✔
2062
    qDebug("%s before add %d elements into histogram, total:%" PRId64 ", numOfEntry:%d, pHisto:%p, elems: %p",
284,389✔
2063
           __FUNCTION__, numOfElems, pInfo->pHisto->numOfElems, pInfo->pHisto->numOfEntries, pInfo->pHisto,
2064
           pInfo->pHisto->elems);
2065
    for (int32_t i = start; i < pInput->numOfRows + start; ++i) {
2,386,823✔
2066
      if (colDataIsNull_f(pCol->nullbitmap, i)) {
2,102,435✔
2067
        continue;
859,108✔
2068
      }
2069
      numOfElems += 1;
1,243,327✔
2070
      char* data = colDataGetData(pCol, i);
1,243,327!
2071

2072
      double v = 0;
1,243,327✔
2073
      GET_TYPED_DATA(v, double, type, data);
1,243,327!
2074
      int32_t code = tHistogramAdd(&pInfo->pHisto, v);
1,243,327✔
2075
      if (code != TSDB_CODE_SUCCESS) {
1,243,320!
2076
        return code;
×
2077
      }
2078
    }
2079

2080
    qDebug("%s after add %d elements into histogram, total:%" PRId64 ", numOfEntry:%d, pHisto:%p, elems: %p",
284,388✔
2081
           __FUNCTION__, numOfElems, pInfo->pHisto->numOfElems, pInfo->pHisto->numOfEntries, pInfo->pHisto,
2082
           pInfo->pHisto->elems);
2083
  }
2084

2085
  SET_VAL(pResInfo, numOfElems, 1);
295,568✔
2086
  return TSDB_CODE_SUCCESS;
295,568✔
2087
}
2088

2089
static int32_t apercentileTransferInfo(SAPercentileInfo* pInput, SAPercentileInfo* pOutput, bool* hasRes) {
8,695✔
2090
  pOutput->percent = pInput->percent;
8,695✔
2091
  pOutput->algo = pInput->algo;
8,695✔
2092
  if (pOutput->algo == APERCT_ALGO_TDIGEST) {
8,695✔
2093
    buildTDigestInfo(pInput);
93✔
2094
    tdigestAutoFill(pInput->pTDigest, COMPRESSION);
93✔
2095

2096
    if (pInput->pTDigest->num_centroids == 0 && pInput->pTDigest->num_buffered_pts == 0) {
93✔
2097
      return TSDB_CODE_SUCCESS;
1✔
2098
    }
2099

2100
    if (hasRes) {
92✔
2101
      *hasRes = true;
90✔
2102
    }
2103

2104
    buildTDigestInfo(pOutput);
92✔
2105
    TDigest* pTDigest = pOutput->pTDigest;
92✔
2106
    tdigestAutoFill(pTDigest, COMPRESSION);
92✔
2107

2108
    if (pTDigest->num_centroids <= 0 && pTDigest->num_buffered_pts == 0) {
92!
2109
      (void)memcpy(pTDigest, pInput->pTDigest, (size_t)TDIGEST_SIZE(COMPRESSION));
90✔
2110
      tdigestAutoFill(pTDigest, COMPRESSION);
90✔
2111
    } else {
2112
      int32_t code = tdigestMerge(pTDigest, pInput->pTDigest);
2✔
2113
      if (TSDB_CODE_SUCCESS != code) {
2!
2114
        return code;
×
2115
      }
2116
    }
2117
  } else {
2118
    buildHistogramInfo(pInput);
8,602✔
2119
    if (pInput->pHisto->numOfElems <= 0) {
8,602✔
2120
      return TSDB_CODE_SUCCESS;
172✔
2121
    }
2122

2123
    if (hasRes) {
8,430✔
2124
      *hasRes = true;
8,428✔
2125
    }
2126

2127
    buildHistogramInfo(pOutput);
8,430✔
2128
    SHistogramInfo* pHisto = pOutput->pHisto;
8,430✔
2129

2130
    if (pHisto->numOfElems <= 0) {
8,430✔
2131
      (void)memcpy(pHisto, pInput->pHisto, sizeof(SHistogramInfo) + sizeof(SHistBin) * (MAX_HISTOGRAM_BIN + 1));
8,004✔
2132
      pHisto->elems = (SHistBin*)((char*)pHisto + sizeof(SHistogramInfo));
8,004✔
2133

2134
      qDebug("%s merge histo, total:%" PRId64 ", entry:%d, %p", __FUNCTION__, pHisto->numOfElems, pHisto->numOfEntries,
8,004✔
2135
             pHisto);
2136
    } else {
2137
      pHisto->elems = (SHistBin*)((char*)pHisto + sizeof(SHistogramInfo));
426✔
2138
      qDebug("%s input histogram, elem:%" PRId64 ", entry:%d, %p", __FUNCTION__, pHisto->numOfElems,
426✔
2139
             pHisto->numOfEntries, pInput->pHisto);
2140

2141
      SHistogramInfo* pRes = NULL;
426✔
2142
      int32_t         code = tHistogramMerge(pHisto, pInput->pHisto, MAX_HISTOGRAM_BIN, &pRes);
426✔
2143
      if (TSDB_CODE_SUCCESS != code) {
426!
2144
        tHistogramDestroy(&pRes);
×
2145
        return code;
×
2146
      }
2147
      (void)memcpy(pHisto, pRes, sizeof(SHistogramInfo) + sizeof(SHistBin) * MAX_HISTOGRAM_BIN);
426✔
2148
      pHisto->elems = (SHistBin*)((char*)pHisto + sizeof(SHistogramInfo));
426✔
2149

2150
      qDebug("%s merge histo, total:%" PRId64 ", entry:%d, %p", __FUNCTION__, pHisto->numOfElems, pHisto->numOfEntries,
426✔
2151
             pHisto);
2152
      tHistogramDestroy(&pRes);
426✔
2153
    }
2154
  }
2155
  return TSDB_CODE_SUCCESS;
8,522✔
2156
}
2157

2158
int32_t apercentileFunctionMerge(SqlFunctionCtx* pCtx) {
8,637✔
2159
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
8,637✔
2160

2161
  SInputColumnInfoData* pInput = &pCtx->input;
8,637✔
2162

2163
  SColumnInfoData* pCol = pInput->pData[0];
8,637✔
2164
  if (pCol->info.type != TSDB_DATA_TYPE_BINARY) {
8,637!
2165
    return TSDB_CODE_FUNC_FUNTION_PARA_TYPE;
×
2166
  }
2167

2168
  SAPercentileInfo* pInfo = GET_ROWCELL_INTERBUF(pResInfo);
8,637✔
2169

2170
  qDebug("%s total %" PRId64 " rows will merge, %p", __FUNCTION__, pInput->numOfRows, pInfo->pHisto);
8,637✔
2171

2172
  bool    hasRes = false;
8,637✔
2173
  int32_t start = pInput->startRowIndex;
8,637✔
2174
  for (int32_t i = start; i < start + pInput->numOfRows; ++i) {
17,328✔
2175
    char* data = colDataGetData(pCol, i);
8,691!
2176

2177
    SAPercentileInfo* pInputInfo = (SAPercentileInfo*)varDataVal(data);
8,691✔
2178
    int32_t           code = apercentileTransferInfo(pInputInfo, pInfo, &hasRes);
8,691✔
2179
    if (TSDB_CODE_SUCCESS != code) {
8,691!
2180
      return code;
×
2181
    }
2182
  }
2183

2184
  if (pInfo->algo != APERCT_ALGO_TDIGEST) {
8,637✔
2185
    buildHistogramInfo(pInfo);
8,546✔
2186
    qDebug("%s after merge, total:%" PRId64 ", numOfEntry:%d, %p", __FUNCTION__, pInfo->pHisto->numOfElems,
8,546✔
2187
           pInfo->pHisto->numOfEntries, pInfo->pHisto);
2188
  }
2189

2190
  SET_VAL(pResInfo, hasRes ? 1 : 0, 1);
8,637✔
2191
  return TSDB_CODE_SUCCESS;
8,637✔
2192
}
2193

2194
int32_t apercentileFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
256,386✔
2195
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
256,386✔
2196
  SAPercentileInfo*    pInfo = (SAPercentileInfo*)GET_ROWCELL_INTERBUF(pResInfo);
256,386✔
2197

2198
  if (pInfo->algo == APERCT_ALGO_TDIGEST) {
256,386✔
2199
    buildTDigestInfo(pInfo);
11,076✔
2200
    tdigestAutoFill(pInfo->pTDigest, COMPRESSION);
11,076✔
2201
    if (pInfo->pTDigest->size > 0) {
11,076!
2202
      pInfo->result = tdigestQuantile(pInfo->pTDigest, pInfo->percent / 100);
11,076✔
2203
    } else {  // no need to free
2204
      // setNull(pCtx->pOutput, pCtx->outputType, pCtx->outputBytes);
2205
      return TSDB_CODE_SUCCESS;
×
2206
    }
2207
  } else {
2208
    buildHistogramInfo(pInfo);
245,310✔
2209
    if (pInfo->pHisto->numOfElems > 0) {
245,308✔
2210
      qDebug("%s get the final res, elements:%" PRId64 ", numOfEntry:%d, pHisto:%p, elems:%p", __FUNCTION__,
185,605✔
2211
             pInfo->pHisto->numOfElems, pInfo->pHisto->numOfEntries, pInfo->pHisto, pInfo->pHisto->elems);
2212

2213
      double  ratio[] = {pInfo->percent};
185,605✔
2214
      double* res = NULL;
185,605✔
2215
      int32_t code = tHistogramUniform(pInfo->pHisto, ratio, 1, &res);
185,605✔
2216
      if (TSDB_CODE_SUCCESS != code) {
185,605!
2217
        taosMemoryFree(res);
×
2218
        return code;
×
2219
      }
2220
      pInfo->result = *res;
185,605✔
2221
      // memcpy(pCtx->pOutput, res, sizeof(double));
2222
      taosMemoryFree(res);
185,605✔
2223
    } else {  // no need to free
2224
      // setNull(pCtx->pOutput, pCtx->outputType, pCtx->outputBytes);
2225
      // return TSDB_CODE_SUCCESS;
2226
      qDebug("%s get the final res, elements:%" PRId64 ", numOfEntry:%d. result is null", __FUNCTION__,
59,703✔
2227
             pInfo->pHisto->numOfElems, pInfo->pHisto->numOfEntries);
2228
    }
2229
  }
2230

2231
  return functionFinalize(pCtx, pBlock);
256,385✔
2232
}
2233

2234
int32_t apercentilePartialFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
8,358✔
2235
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
8,358✔
2236
  SAPercentileInfo*    pInfo = (SAPercentileInfo*)GET_ROWCELL_INTERBUF(pResInfo);
8,358✔
2237

2238
  int32_t resultBytes = getApercentileMaxSize();
8,358✔
2239
  char*   res = taosMemoryCalloc(resultBytes + VARSTR_HEADER_SIZE, sizeof(char));
8,358!
2240
  if (NULL == res) {
8,358!
2241
    return terrno;
×
2242
  }
2243

2244
  if (pInfo->algo == APERCT_ALGO_TDIGEST) {
8,358✔
2245
    (void)memcpy(varDataVal(res), pInfo, resultBytes);
91✔
2246
    varDataSetLen(res, resultBytes);
91✔
2247
  } else {
2248
    (void)memcpy(varDataVal(res), pInfo, resultBytes);
8,267✔
2249
    varDataSetLen(res, resultBytes);
8,267✔
2250
  }
2251

2252
  int32_t          slotId = pCtx->pExpr->base.resSchema.slotId;
8,358✔
2253
  SColumnInfoData* pCol = taosArrayGet(pBlock->pDataBlock, slotId);
8,358✔
2254
  if (NULL == pCol) {
8,358!
2255
    taosMemoryFree(res);
×
2256
    return TSDB_CODE_OUT_OF_RANGE;
×
2257
  }
2258

2259
  int32_t code = colDataSetVal(pCol, pBlock->info.rows, res, false);
8,358✔
2260

2261
  taosMemoryFree(res);
8,358!
2262
  return code;
8,358✔
2263
}
2264

2265
int32_t apercentileCombine(SqlFunctionCtx* pDestCtx, SqlFunctionCtx* pSourceCtx) {
4✔
2266
  SResultRowEntryInfo* pDResInfo = GET_RES_INFO(pDestCtx);
4✔
2267
  SAPercentileInfo*    pDBuf = GET_ROWCELL_INTERBUF(pDResInfo);
4✔
2268

2269
  SResultRowEntryInfo* pSResInfo = GET_RES_INFO(pSourceCtx);
4✔
2270
  SAPercentileInfo*    pSBuf = GET_ROWCELL_INTERBUF(pSResInfo);
4✔
2271

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

2274
  int32_t code = apercentileTransferInfo(pSBuf, pDBuf, NULL);
4✔
2275
  if (TSDB_CODE_SUCCESS != code) {
4!
2276
    return code;
×
2277
  }
2278
  pDResInfo->numOfRes = TMAX(pDResInfo->numOfRes, pSResInfo->numOfRes);
4✔
2279
  pDResInfo->isNullRes &= pSResInfo->isNullRes;
4✔
2280
  return TSDB_CODE_SUCCESS;
4✔
2281
}
2282

2283
// TODO: change this function when block data info pks changed
2284
static int32_t comparePkDataWithSValue(int8_t pkType, char* pkData, SValue* pVal, int32_t order) {
11✔
2285
  char numVal[8] = {0};
11✔
2286
  switch (pkType) {
11!
2287
    case TSDB_DATA_TYPE_INT:
11✔
2288
      *(int32_t*)numVal = (int32_t)pVal->val;
11✔
2289
      break;
11✔
2290
    case TSDB_DATA_TYPE_UINT:
×
2291
      *(uint32_t*)numVal = (uint32_t)pVal->val;
×
2292
      break;
×
2293
    case TSDB_DATA_TYPE_BIGINT:
×
2294
      *(int64_t*)numVal = (int64_t)pVal->val;
×
2295
      break;
×
2296
    case TSDB_DATA_TYPE_UBIGINT:
×
2297
      *(uint64_t*)numVal = (uint64_t)pVal->val;
×
2298
      break;
×
2299
    default:
×
2300
      break;
×
2301
  }
2302
  char*         blockData = (IS_NUMERIC_TYPE(pkType)) ? (char*)numVal : (char*)pVal->pData;
11!
2303
  __compar_fn_t fn = getKeyComparFunc(pkType, order);
11✔
2304
  return fn(pkData, blockData);
11✔
2305
}
2306

2307
EFuncDataRequired firstDynDataReq(void* pRes, SDataBlockInfo* pBlockInfo) {
969✔
2308
  SResultRowEntryInfo* pEntry = (SResultRowEntryInfo*)pRes;
969✔
2309

2310
  // not initialized yet, data is required
2311
  if (pEntry == NULL) {
969!
2312
    return FUNC_DATA_REQUIRED_DATA_LOAD;
×
2313
  }
2314

2315
  SFirstLastRes* pResult = GET_ROWCELL_INTERBUF(pEntry);
969✔
2316
  if (pResult->hasResult) {
969✔
2317
    if (pResult->pkBytes > 0) {
905✔
2318
      pResult->pkData = pResult->buf + pResult->bytes;
6✔
2319
    } else {
2320
      pResult->pkData = NULL;
899✔
2321
    }
2322
    if (pResult->ts < pBlockInfo->window.skey) {
905✔
2323
      return FUNC_DATA_REQUIRED_NOT_LOAD;
195✔
2324
    } else if (pResult->ts == pBlockInfo->window.skey) {
710✔
2325
      if (NULL == pResult->pkData) {
194✔
2326
        return FUNC_DATA_REQUIRED_NOT_LOAD;
188✔
2327
      }
2328
      if (comparePkDataWithSValue(pResult->pkType, pResult->pkData, pBlockInfo->pks + 0, TSDB_ORDER_ASC) < 0) {
6!
2329
        return FUNC_DATA_REQUIRED_NOT_LOAD;
6✔
2330
      }
2331
    }
2332
    return FUNC_DATA_REQUIRED_DATA_LOAD;
516✔
2333
  } else {
2334
    return FUNC_DATA_REQUIRED_DATA_LOAD;
64✔
2335
  }
2336
}
2337

2338
EFuncDataRequired lastDynDataReq(void* pRes, SDataBlockInfo* pBlockInfo) {
1,433✔
2339
  SResultRowEntryInfo* pEntry = (SResultRowEntryInfo*)pRes;
1,433✔
2340

2341
  // not initialized yet, data is required
2342
  if (pEntry == NULL) {
1,433!
2343
    return FUNC_DATA_REQUIRED_DATA_LOAD;
×
2344
  }
2345

2346
  SFirstLastRes* pResult = GET_ROWCELL_INTERBUF(pEntry);
1,433✔
2347
  if (pResult->hasResult) {
1,433✔
2348
    if (pResult->pkBytes > 0) {
1,346✔
2349
      pResult->pkData = pResult->buf + pResult->bytes;
5✔
2350
    } else {
2351
      pResult->pkData = NULL;
1,341✔
2352
    }
2353
    if (pResult->ts > pBlockInfo->window.ekey) {
1,346✔
2354
      return FUNC_DATA_REQUIRED_NOT_LOAD;
372✔
2355
    } else if (pResult->ts == pBlockInfo->window.ekey && pResult->pkData) {
974✔
2356
      if (comparePkDataWithSValue(pResult->pkType, pResult->pkData, pBlockInfo->pks + 1, TSDB_ORDER_DESC) < 0) {
5!
2357
        return FUNC_DATA_REQUIRED_NOT_LOAD;
×
2358
      }
2359
    }
2360
    return FUNC_DATA_REQUIRED_DATA_LOAD;
974✔
2361
  } else {
2362
    return FUNC_DATA_REQUIRED_DATA_LOAD;
87✔
2363
  }
2364
}
2365

2366
// TODO modify it to include primary key bytes
2367
int32_t getFirstLastInfoSize(int32_t resBytes, int32_t pkBytes) { return sizeof(SFirstLastRes) + resBytes + pkBytes; }
22,894,215✔
2368

2369
bool getFirstLastFuncEnv(SFunctionNode* pFunc, SFuncExecEnv* pEnv) {
147,828✔
2370
  SColumnNode* pNode = (SColumnNode*)nodesListGetNode(pFunc->pParameterList, 0);
147,828✔
2371
  // TODO: change SFunctionNode to add pk info
2372
  int32_t pkBytes = (pFunc->hasPk) ? pFunc->pkBytes : 0;
147,881✔
2373
  pEnv->calcMemSize = getFirstLastInfoSize(pNode->node.resType.bytes, pkBytes);
147,881✔
2374
  return true;
147,865✔
2375
}
2376

2377
bool getSelectivityFuncEnv(SFunctionNode* pFunc, SFuncExecEnv* pEnv) {
46,361✔
2378
  SColumnNode* pNode = (SColumnNode*)nodesListGetNode(pFunc->pParameterList, 0);
46,361✔
2379
  pEnv->calcMemSize = pNode->node.resType.bytes;
46,367✔
2380
  return true;
46,367✔
2381
}
2382

2383
bool getGroupKeyFuncEnv(SFunctionNode* pFunc, SFuncExecEnv* pEnv) {
228,989✔
2384
  SColumnNode* pNode = (SColumnNode*)nodesListGetNode(pFunc->pParameterList, 0);
228,989✔
2385
  pEnv->calcMemSize = sizeof(SGroupKeyInfo) + pNode->node.resType.bytes;
229,263✔
2386
  return true;
229,263✔
2387
}
2388

2389
static FORCE_INLINE TSKEY getRowPTs(SColumnInfoData* pTsColInfo, int32_t rowIndex) {
2390
  if (pTsColInfo == NULL || pTsColInfo->pData == NULL) {
95,866,089!
2391
    return 0;
×
2392
  }
2393

2394
  return *(TSKEY*)colDataGetData(pTsColInfo, rowIndex);
95,922,034!
2395
}
2396

2397
int32_t firstLastFunctionSetup(SqlFunctionCtx* pCtx, SResultRowEntryInfo* pResInfo) {
1,093,680✔
2398
  if (pResInfo->initialized) {
1,093,680!
2399
    return TSDB_CODE_SUCCESS;
×
2400
  }
2401
  if (TSDB_CODE_SUCCESS != functionSetup(pCtx, pResInfo)) {
1,093,680!
2402
    return TSDB_CODE_FUNC_SETUP_ERROR;
×
2403
  }
2404

2405
  SFirstLastRes*        pRes = GET_ROWCELL_INTERBUF(pResInfo);
1,093,683✔
2406
  SInputColumnInfoData* pInput = &pCtx->input;
1,093,683✔
2407

2408
  pRes->nullTupleSaved = false;
1,093,683✔
2409
  pRes->nullTuplePos.pageId = -1;
1,093,683✔
2410
  return TSDB_CODE_SUCCESS;
1,093,683✔
2411
}
2412

2413
static int32_t prepareBuf(SqlFunctionCtx* pCtx) {
399,462✔
2414
  if (pCtx->subsidiaries.rowLen == 0) {
399,462✔
2415
    int32_t rowLen = 0;
16,111✔
2416
    for (int32_t j = 0; j < pCtx->subsidiaries.num; ++j) {
36,996✔
2417
      SqlFunctionCtx* pc = pCtx->subsidiaries.pCtx[j];
20,885✔
2418
      rowLen += pc->pExpr->base.resSchema.bytes;
20,885✔
2419
    }
2420

2421
    pCtx->subsidiaries.rowLen = rowLen + pCtx->subsidiaries.num * sizeof(bool);
16,111✔
2422
    pCtx->subsidiaries.buf = taosMemoryMalloc(pCtx->subsidiaries.rowLen);
16,111!
2423
    if (NULL == pCtx->subsidiaries.buf) {
16,104!
2424
      return terrno;
×
2425
    }
2426
  }
2427
  return TSDB_CODE_SUCCESS;
399,455✔
2428
}
2429

2430
static int32_t firstlastSaveTupleData(const SSDataBlock* pSrcBlock, int32_t rowIndex, SqlFunctionCtx* pCtx,
52,040,241✔
2431
                                      SFirstLastRes* pInfo, bool noElements) {
2432
  int32_t code = TSDB_CODE_SUCCESS;
52,040,241✔
2433

2434
  if (pCtx->subsidiaries.num <= 0) {
52,040,241!
2435
    return TSDB_CODE_SUCCESS;
52,044,659✔
2436
  }
2437

2438
  if (!pInfo->hasResult) {
×
2439
    code = saveTupleData(pCtx, rowIndex, pSrcBlock, noElements ? &pInfo->nullTuplePos : &pInfo->pos);
9,446✔
2440
  } else {
2441
    code = updateTupleData(pCtx, rowIndex, pSrcBlock, &pInfo->pos);
×
2442
  }
2443

2444
  return code;
9,985✔
2445
}
2446

2447
static int32_t doSaveCurrentVal(SqlFunctionCtx* pCtx, int32_t rowIndex, int64_t currentTs, char* pkData, int32_t type,
29,510,542✔
2448
                                char* pData) {
2449
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
29,510,542✔
2450
  SFirstLastRes*       pInfo = GET_ROWCELL_INTERBUF(pResInfo);
29,510,542✔
2451

2452
  if (IS_VAR_DATA_TYPE(type)) {
29,510,542!
2453
    if (type == TSDB_DATA_TYPE_JSON) {
177,710!
2454
      pInfo->bytes = getJsonValueLen(pData);
×
2455
    } else {
2456
      pInfo->bytes = varDataTLen(pData);
177,710✔
2457
    }
2458
  }
2459

2460
  (void)memcpy(pInfo->buf, pData, pInfo->bytes);
29,510,542✔
2461
  if (pkData != NULL) {
29,510,542✔
2462
    if (IS_VAR_DATA_TYPE(pInfo->pkType)) {
30,118!
2463
      if (pInfo->pkType == TSDB_DATA_TYPE_JSON) {
24!
2464
        pInfo->pkBytes = getJsonValueLen(pkData);
×
2465
      } else {
2466
        pInfo->pkBytes = varDataTLen(pkData);
24✔
2467
      }
2468
    }
2469
    (void)memcpy(pInfo->buf + pInfo->bytes, pkData, pInfo->pkBytes);
30,118✔
2470
    pInfo->pkData = pInfo->buf + pInfo->bytes;
30,118✔
2471
  }
2472

2473
  pInfo->ts = currentTs;
29,510,542✔
2474
  int32_t code = firstlastSaveTupleData(pCtx->pSrcBlock, rowIndex, pCtx, pInfo, false);
29,510,542✔
2475
  if (code != TSDB_CODE_SUCCESS) {
29,567,385!
2476
    return code;
×
2477
  }
2478

2479
  pInfo->hasResult = true;
29,567,385✔
2480
  return TSDB_CODE_SUCCESS;
29,567,385✔
2481
}
2482

2483
// This ordinary first function does not care if current scan is ascending order or descending order scan
2484
// the OPTIMIZED version of first function will only handle the ascending order scan
2485
int32_t firstFunction(SqlFunctionCtx* pCtx) {
28,894,250✔
2486
  int32_t numOfElems = 0;
28,894,250✔
2487

2488
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
28,894,250✔
2489
  SFirstLastRes*       pInfo = GET_ROWCELL_INTERBUF(pResInfo);
28,894,250✔
2490

2491
  SInputColumnInfoData* pInput = &pCtx->input;
28,894,250✔
2492
  SColumnInfoData*      pInputCol = pInput->pData[0];
28,894,250✔
2493

2494
  pInfo->bytes = pInputCol->info.bytes;
28,894,250✔
2495

2496
  if (IS_NULL_TYPE(pInputCol->info.type)) {
28,894,250✔
2497
    return TSDB_CODE_SUCCESS;
2,037✔
2498
  }
2499

2500
  SColumnInfoData* pkCol = pInput->pPrimaryKey;
28,892,213✔
2501
  pInfo->pkType = -1;
28,892,213✔
2502
  __compar_fn_t pkCompareFn = NULL;
28,892,213✔
2503
  if (pCtx->hasPrimaryKey) {
28,892,213✔
2504
    pInfo->pkType = pkCol->info.type;
51✔
2505
    pInfo->pkBytes = pkCol->info.bytes;
51✔
2506
    pkCompareFn = getKeyComparFunc(pInfo->pkType, TSDB_ORDER_ASC);
51✔
2507
  }
2508

2509
  // All null data column, return directly.
2510
  if (pInput->colDataSMAIsSet && (pInput->pColumnDataAgg[0]->numOfNull == pInput->totalRows) &&
28,961,249!
2511
      pInputCol->hasNull == true) {
×
2512
    // save selectivity value for column consisted of all null values
2513
    int32_t code = firstlastSaveTupleData(pCtx->pSrcBlock, pInput->startRowIndex, pCtx, pInfo, !pInfo->nullTupleSaved);
×
2514
    if (code != TSDB_CODE_SUCCESS) {
×
2515
      return code;
×
2516
    }
2517
    pInfo->nullTupleSaved = true;
×
2518
    return TSDB_CODE_SUCCESS;
×
2519
  }
2520

2521
  SColumnDataAgg* pColAgg = (pInput->colDataSMAIsSet) ? pInput->pColumnDataAgg[0] : NULL;
28,961,249!
2522

2523
  TSKEY startKey = getRowPTs(pInput->pPTS, 0);
28,961,249!
2524
  TSKEY endKey = getRowPTs(pInput->pPTS, pInput->totalRows - 1);
28,961,249!
2525

2526
  int32_t blockDataOrder = (startKey <= endKey) ? TSDB_ORDER_ASC : TSDB_ORDER_DESC;
28,961,249✔
2527

2528
  //  please ref. to the comment in lastRowFunction for the reason why disabling the opt version of last/first
2529
  //  function. we will use this opt implementation in an new version that is only available in scan subplan
2530
#if 0
2531
  if (blockDataOrder == TSDB_ORDER_ASC) {
2532
    // filter according to current result firstly
2533
    if (pResInfo->numOfRes > 0) {
2534
      if (pInfo->ts < startKey) {
2535
        return TSDB_CODE_SUCCESS;
2536
      }
2537
    }
2538

2539
    for (int32_t i = pInput->startRowIndex; i < pInput->startRowIndex + pInput->numOfRows; ++i) {
2540
      if (pInputCol->hasNull && colDataIsNull(pInputCol, pInput->totalRows, i, pColAgg)) {
2541
        continue;
2542
      }
2543

2544
      numOfElems++;
2545

2546
      char* data = colDataGetData(pInputCol, i);
2547
      TSKEY cts = getRowPTs(pInput->pPTS, i);
2548
      if (pResInfo->numOfRes == 0 || pInfo->ts > cts) {
2549
        doSaveCurrentVal(pCtx, i, cts, pInputCol->info.type, data);
2550
        break;
2551
      }
2552
    }
2553
  } else {
2554
    // in case of descending order time stamp serial, which usually happens as the results of the nest query,
2555
    // all data needs to be check.
2556
    if (pResInfo->numOfRes > 0) {
2557
      if (pInfo->ts < endKey) {
2558
        return TSDB_CODE_SUCCESS;
2559
      }
2560
    }
2561

2562
    for (int32_t i = pInput->numOfRows + pInput->startRowIndex - 1; i >= pInput->startRowIndex; --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

2572
      if (pResInfo->numOfRes == 0 || pInfo->ts > cts) {
2573
        doSaveCurrentVal(pCtx, i, cts, pInputCol->info.type, data);
2574
        break;
2575
      }
2576
    }
2577
  }
2578
#else
2579
  int64_t* pts = (int64_t*)pInput->pPTS->pData;
28,961,249✔
2580

2581
  int     from = -1;
28,961,249✔
2582
  int32_t i = -1;
28,961,249✔
2583
  while (funcInputGetNextRowIndex(pInput, from, true, &i, &from)) {
75,965,499✔
2584
    if (pInputCol->hasNull && colDataIsNull(pInputCol, pInput->totalRows, i, pColAgg)) {
60,810,711!
2585
      continue;
69,593✔
2586
    }
2587

2588
    numOfElems++;
46,945,684✔
2589
    char* data = colDataGetData(pInputCol, i);
46,945,684!
2590
    char* pkData = NULL;
46,945,684✔
2591
    if (pCtx->hasPrimaryKey) {
46,945,684✔
2592
      pkData = colDataGetData(pkCol, i);
153!
2593
    }
2594
    TSKEY cts = pts[i];
46,945,684✔
2595
    if (pResInfo->numOfRes == 0 || pInfo->ts > cts ||
46,945,684✔
2596
        (pInfo->ts == cts && pkCompareFn && pkCompareFn(pkData, pInfo->pkData) < 0)) {
29,160,870!
2597
      int32_t code = doSaveCurrentVal(pCtx, i, cts, pkData, pInputCol->info.type, data);
17,784,814✔
2598
      if (code != TSDB_CODE_SUCCESS) {
17,773,787!
2599
        return code;
×
2600
      }
2601
      pResInfo->numOfRes = 1;
17,773,787✔
2602
    }
2603
  }
2604
#endif
2605

2606
  if (numOfElems == 0) {
28,284,091✔
2607
    // save selectivity value for column consisted of all null values
2608
    int32_t code = firstlastSaveTupleData(pCtx->pSrcBlock, pInput->startRowIndex, pCtx, pInfo, !pInfo->nullTupleSaved);
24,491✔
2609
    if (code != TSDB_CODE_SUCCESS) {
24,491!
2610
      return code;
×
2611
    }
2612
    pInfo->nullTupleSaved = true;
24,491✔
2613
  }
2614
  SET_VAL(pResInfo, numOfElems, 1);
28,284,091✔
2615
  return TSDB_CODE_SUCCESS;
28,284,091✔
2616
}
2617

2618
int32_t lastFunction(SqlFunctionCtx* pCtx) {
18,743,805✔
2619
  int32_t numOfElems = 0;
18,743,805✔
2620

2621
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
18,743,805✔
2622
  SFirstLastRes*       pInfo = GET_ROWCELL_INTERBUF(pResInfo);
18,743,805✔
2623

2624
  SInputColumnInfoData* pInput = &pCtx->input;
18,743,805✔
2625
  SColumnInfoData*      pInputCol = pInput->pData[0];
18,743,805✔
2626

2627
  int32_t type = pInputCol->info.type;
18,743,805✔
2628
  int32_t bytes = pInputCol->info.bytes;
18,743,805✔
2629
  pInfo->bytes = bytes;
18,743,805✔
2630

2631
  if (IS_NULL_TYPE(type)) {
18,743,805✔
2632
    return TSDB_CODE_SUCCESS;
2,037✔
2633
  }
2634

2635
  SColumnInfoData* pkCol = pInput->pPrimaryKey;
18,741,768✔
2636
  pInfo->pkType = -1;
18,741,768✔
2637
  __compar_fn_t pkCompareFn = NULL;
18,741,768✔
2638
  if (pCtx->hasPrimaryKey) {
18,741,768✔
2639
    pInfo->pkType = pkCol->info.type;
30,067✔
2640
    pInfo->pkBytes = pkCol->info.bytes;
30,067✔
2641
    pkCompareFn = getKeyComparFunc(pInfo->pkType, TSDB_ORDER_DESC);
30,067✔
2642
  }
2643

2644
  // All null data column, return directly.
2645
  if (pInput->colDataSMAIsSet && (pInput->pColumnDataAgg[0]->numOfNull == pInput->totalRows) &&
18,798,746!
2646
      pInputCol->hasNull == true) {
×
2647
    // save selectivity value for column consisted of all null values
2648
    int32_t code = firstlastSaveTupleData(pCtx->pSrcBlock, pInput->startRowIndex, pCtx, pInfo, !pInfo->nullTupleSaved);
×
2649
    if (code != TSDB_CODE_SUCCESS) {
×
2650
      return code;
×
2651
    }
2652
    pInfo->nullTupleSaved = true;
×
2653
    return TSDB_CODE_SUCCESS;
×
2654
  }
2655

2656
  SColumnDataAgg* pColAgg = (pInput->colDataSMAIsSet) ? pInput->pColumnDataAgg[0] : NULL;
18,798,746!
2657

2658
  TSKEY startKey = getRowPTs(pInput->pPTS, 0);
18,798,746!
2659
  TSKEY endKey = getRowPTs(pInput->pPTS, pInput->totalRows - 1);
18,798,746!
2660

2661
  int32_t blockDataOrder = (startKey <= endKey) ? TSDB_ORDER_ASC : TSDB_ORDER_DESC;
18,798,746✔
2662

2663
  //  please ref. to the comment in lastRowFunction for the reason why disabling the opt version of last/first function.
2664
#if 0
2665
  if (blockDataOrder == TSDB_ORDER_ASC) {
2666
    for (int32_t i = pInput->numOfRows + pInput->startRowIndex - 1; i >= pInput->startRowIndex; --i) {
2667
      if (pInputCol->hasNull && colDataIsNull(pInputCol, pInput->totalRows, i, pColAgg)) {
2668
        continue;
2669
      }
2670

2671
      numOfElems++;
2672

2673
      char* data = colDataGetData(pInputCol, i);
2674
      TSKEY cts = getRowPTs(pInput->pPTS, i);
2675
      if (pResInfo->numOfRes == 0 || pInfo->ts < cts) {
2676
        doSaveCurrentVal(pCtx, i, cts, type, data);
2677
      }
2678

2679
      break;
2680
    }
2681
  } else {  // descending order
2682
    for (int32_t i = pInput->startRowIndex; i < pInput->numOfRows + pInput->startRowIndex; ++i) {
2683
      if (pInputCol->hasNull && colDataIsNull(pInputCol, pInput->totalRows, i, pColAgg)) {
2684
        continue;
2685
      }
2686

2687
      numOfElems++;
2688

2689
      char* data = colDataGetData(pInputCol, i);
2690
      TSKEY cts = getRowPTs(pInput->pPTS, i);
2691
      if (pResInfo->numOfRes == 0 || pInfo->ts < cts) {
2692
        doSaveCurrentVal(pCtx, i, cts, type, data);
2693
      }
2694
      break;
2695
    }
2696
  }
2697
#else
2698
  int64_t* pts = (int64_t*)pInput->pPTS->pData;
18,798,746✔
2699

2700
#if 0
2701
    for (int32_t i = pInput->startRowIndex; i < pInput->numOfRows + pInput->startRowIndex; ++i) {
2702
      if (pInputCol->hasNull && colDataIsNull(pInputCol, pInput->totalRows, i, pColAgg)) {
2703
        continue;
2704
      }
2705

2706
      numOfElems++;
2707
      if (pResInfo->numOfRes == 0 || pInfo->ts < pts[i]) {
2708
        char* data = colDataGetData(pInputCol, i);
2709
        doSaveCurrentVal(pCtx, i, pts[i], type, data);
2710
        pResInfo->numOfRes = 1;
2711
      }
2712
    }
2713
#else
2714

2715
  // todo refactor
2716
  if (!pInputCol->hasNull && !pCtx->hasPrimaryKey) {
31,205,483✔
2717
    numOfElems = 1;
12,411,855✔
2718

2719
    int32_t round = pInput->numOfRows >> 2;
12,411,855✔
2720
    int32_t reminder = pInput->numOfRows & 0x03;
12,411,855✔
2721

2722
    for (int32_t i = pInput->startRowIndex, tick = 0; tick < round; i += 4, tick += 1) {
18,748,776✔
2723
      int64_t cts = pts[i];
6,331,148✔
2724
      int32_t chosen = i;
6,331,148✔
2725

2726
      if (cts < pts[i + 1]) {
6,331,148✔
2727
        cts = pts[i + 1];
3,838,820✔
2728
        chosen = i + 1;
3,838,820✔
2729
      }
2730

2731
      if (cts < pts[i + 2]) {
6,331,148✔
2732
        cts = pts[i + 2];
3,838,813✔
2733
        chosen = i + 2;
3,838,813✔
2734
      }
2735

2736
      if (cts < pts[i + 3]) {
6,331,148✔
2737
        cts = pts[i + 3];
3,837,905✔
2738
        chosen = i + 3;
3,837,905✔
2739
      }
2740

2741
      if (pResInfo->numOfRes == 0 || pInfo->ts < cts) {
6,331,148✔
2742
        char*   data = colDataGetData(pInputCol, chosen);
2,324,399!
2743
        int32_t code = doSaveCurrentVal(pCtx, i, cts, NULL, type, data);
2,324,399✔
2744
        if (code != TSDB_CODE_SUCCESS) {
2,330,172!
2745
          return code;
×
2746
        }
2747
        pResInfo->numOfRes = 1;
2,330,172✔
2748
      }
2749
    }
2750

2751
    for (int32_t i = pInput->startRowIndex + round * 4; i < pInput->startRowIndex + pInput->numOfRows; ++i) {
26,009,273✔
2752
      if (pResInfo->numOfRes == 0 || pInfo->ts < pts[i]) {
13,602,536✔
2753
        char*   data = colDataGetData(pInputCol, i);
5,876,517!
2754
        int32_t code = doSaveCurrentVal(pCtx, i, pts[i], NULL, type, data);
5,876,517✔
2755
        if (code != TSDB_CODE_SUCCESS) {
5,865,626!
2756
          return code;
×
2757
        }
2758
        pResInfo->numOfRes = 1;
5,865,626✔
2759
      }
2760
    }
2761
  } else {
2762
    int     from = -1;
6,386,891✔
2763
    int32_t i = -1;
6,386,891✔
2764
    while (funcInputGetNextRowIndex(pInput, from, false, &i, &from)) {
123,493,341✔
2765
      if (colDataIsNull(pInputCol, pInput->totalRows, i, pColAgg)) {
234,214,612✔
2766
        continue;
5,575,082✔
2767
      }
2768

2769
      numOfElems++;
111,532,224✔
2770
      char* pkData = NULL;
111,532,224✔
2771
      if (pCtx->hasPrimaryKey) {
111,532,224✔
2772
        pkData = colDataGetData(pkCol, i);
100,000,193!
2773
      }
2774
      if (pResInfo->numOfRes == 0 || pInfo->ts < pts[i] ||
111,532,224✔
2775
          (pInfo->ts == pts[i] && pkCompareFn && pkCompareFn(pkData, pInfo->pkData) < 0)) {
108,107,066!
2776
        char*   data = colDataGetData(pInputCol, i);
3,476,382!
2777
        int32_t code = doSaveCurrentVal(pCtx, i, pts[i], pkData, type, data);
3,476,382✔
2778
        if (code != TSDB_CODE_SUCCESS) {
3,475,526!
2779
          return code;
×
2780
        }
2781
        pResInfo->numOfRes = 1;
3,475,526✔
2782
      }
2783
    }
2784
  }
2785
#endif
2786

2787
#endif
2788

2789
  // save selectivity value for column consisted of all null values
2790
  if (numOfElems == 0) {
18,974,938✔
2791
    int32_t code = firstlastSaveTupleData(pCtx->pSrcBlock, pInput->startRowIndex, pCtx, pInfo, !pInfo->nullTupleSaved);
4,092,790✔
2792
    if (code != TSDB_CODE_SUCCESS) {
4,083,980!
2793
      return code;
×
2794
    }
2795
    pInfo->nullTupleSaved = true;
4,083,980✔
2796
  }
2797

2798
  return TSDB_CODE_SUCCESS;
18,966,128✔
2799
}
2800

2801
static bool firstLastTransferInfoImpl(SFirstLastRes* pInput, SFirstLastRes* pOutput, bool isFirst) {
18,513,247✔
2802
  if (!pInput->hasResult) {
18,513,247✔
2803
    return false;
2✔
2804
  }
2805
  __compar_fn_t pkCompareFn = NULL;
18,513,245✔
2806
  if (pInput->pkData) {
18,513,245✔
2807
    pkCompareFn = getKeyComparFunc(pInput->pkType, (isFirst) ? TSDB_ORDER_ASC : TSDB_ORDER_DESC);
52✔
2808
  }
2809
  if (pOutput->hasResult) {
18,513,245✔
2810
    if (isFirst) {
11,206,396✔
2811
      if (pInput->ts > pOutput->ts ||
8,571,747✔
2812
          (pInput->ts == pOutput->ts && pkCompareFn && pkCompareFn(pInput->pkData, pOutput->pkData) > 0)) {
8,571,167!
2813
        return false;
580✔
2814
      }
2815
    } else {
2816
      if (pInput->ts < pOutput->ts ||
2,634,649✔
2817
          (pInput->ts == pOutput->ts && pkCompareFn && pkCompareFn(pInput->pkData, pOutput->pkData) > 0)) {
2,632,062!
2818
        return false;
2,587✔
2819
      }
2820
    }
2821
  }
2822

2823
  pOutput->isNull = pInput->isNull;
18,510,078✔
2824
  pOutput->ts = pInput->ts;
18,510,078✔
2825
  pOutput->bytes = pInput->bytes;
18,510,078✔
2826
  pOutput->pkType = pInput->pkType;
18,510,078✔
2827

2828
  (void)memcpy(pOutput->buf, pInput->buf, pOutput->bytes);
18,510,078✔
2829
  if (pInput->pkData) {
18,510,078✔
2830
    pOutput->pkBytes = pInput->pkBytes;
48✔
2831
    (void)memcpy(pOutput->buf + pOutput->bytes, pInput->pkData, pOutput->pkBytes);
48✔
2832
    pOutput->pkData = pOutput->buf + pOutput->bytes;
48✔
2833
  }
2834
  return true;
18,510,078✔
2835
}
2836

2837
static int32_t firstLastTransferInfo(SqlFunctionCtx* pCtx, SFirstLastRes* pInput, SFirstLastRes* pOutput, bool isFirst,
18,513,241✔
2838
                                     int32_t rowIndex) {
2839
  if (firstLastTransferInfoImpl(pInput, pOutput, isFirst)) {
18,513,241✔
2840
    int32_t code = firstlastSaveTupleData(pCtx->pSrcBlock, rowIndex, pCtx, pOutput, pOutput->nullTupleSaved);
18,510,075✔
2841
    if (TSDB_CODE_SUCCESS != code) {
18,510,075!
2842
      return code;
×
2843
    }
2844
    pOutput->hasResult = true;
18,510,075✔
2845
  }
2846
  return TSDB_CODE_SUCCESS;
18,513,241✔
2847
}
2848

2849
static int32_t firstLastFunctionMergeImpl(SqlFunctionCtx* pCtx, bool isFirstQuery) {
7,321,361✔
2850
  SInputColumnInfoData* pInput = &pCtx->input;
7,321,361✔
2851
  SColumnInfoData*      pCol = pInput->pData[0];
7,321,361✔
2852

2853
  if (IS_NULL_TYPE(pCol->info.type)) {
7,321,361!
2854
    SET_VAL(GET_RES_INFO(pCtx), 0, 1);
×
2855
    return TSDB_CODE_SUCCESS;
×
2856
  }
2857

2858
  if (pCol->info.type != TSDB_DATA_TYPE_BINARY) {
7,321,361!
2859
    return TSDB_CODE_FUNC_FUNTION_PARA_TYPE;
×
2860
  }
2861

2862
  SFirstLastRes* pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
7,321,361✔
2863

2864
  int32_t start = pInput->startRowIndex;
7,321,361✔
2865
  int32_t numOfElems = 0;
7,321,361✔
2866

2867
  for (int32_t i = start; i < start + pInput->numOfRows; ++i) {
28,119,785✔
2868
    if (colDataIsNull_s(pCol, i)) {
41,596,848✔
2869
      continue;
2,285,183✔
2870
    }
2871
    char*          data = colDataGetData(pCol, i);
18,513,241!
2872
    SFirstLastRes* pInputInfo = (SFirstLastRes*)varDataVal(data);
18,513,241✔
2873
    if (pCtx->hasPrimaryKey) {
18,513,241✔
2874
      pInputInfo->pkData = pInputInfo->buf + pInputInfo->bytes;
52✔
2875
    } else {
2876
      pInputInfo->pkData = NULL;
18,513,189✔
2877
    }
2878

2879
    int32_t code = firstLastTransferInfo(pCtx, pInputInfo, pInfo, isFirstQuery, i);
18,513,241✔
2880
    if (code != TSDB_CODE_SUCCESS) {
18,513,241!
2881
      return code;
×
2882
    }
2883
    if (!numOfElems) {
18,513,241✔
2884
      numOfElems = pInputInfo->hasResult ? 1 : 0;
7,313,370✔
2885
    }
2886
  }
2887

2888
  if (numOfElems == 0) {
7,321,361✔
2889
    int32_t code = firstlastSaveTupleData(pCtx->pSrcBlock, pInput->startRowIndex, pCtx, pInfo, !pInfo->nullTupleSaved);
7,991✔
2890
    if (code != TSDB_CODE_SUCCESS) {
7,991!
2891
      return code;
×
2892
    }
2893
    pInfo->nullTupleSaved = true;
7,991✔
2894
  }
2895

2896
  SET_VAL(GET_RES_INFO(pCtx), numOfElems, 1);
7,321,361✔
2897
  return TSDB_CODE_SUCCESS;
7,321,361✔
2898
}
2899

2900
int32_t firstFunctionMerge(SqlFunctionCtx* pCtx) { return firstLastFunctionMergeImpl(pCtx, true); }
4,268,015✔
2901

2902
int32_t lastFunctionMerge(SqlFunctionCtx* pCtx) { return firstLastFunctionMergeImpl(pCtx, false); }
3,053,346✔
2903

2904
int32_t firstLastFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
8,843,039✔
2905
  int32_t          code = TSDB_CODE_SUCCESS;
8,843,039✔
2906
  int32_t          slotId = pCtx->pExpr->base.resSchema.slotId;
8,843,039✔
2907
  SColumnInfoData* pCol = taosArrayGet(pBlock->pDataBlock, slotId);
8,843,039✔
2908
  if (NULL == pCol) {
8,843,039!
2909
    return TSDB_CODE_OUT_OF_RANGE;
×
2910
  }
2911

2912
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
8,843,039✔
2913
  pResInfo->isNullRes = (pResInfo->numOfRes == 0) ? 1 : 0;
8,843,039✔
2914

2915
  SFirstLastRes* pRes = GET_ROWCELL_INTERBUF(pResInfo);
8,843,039✔
2916

2917
  if (pResInfo->isNullRes) {
8,843,039✔
2918
    colDataSetNULL(pCol, pBlock->info.rows);
34,288✔
2919
    return setSelectivityValue(pCtx, pBlock, &pRes->nullTuplePos, pBlock->info.rows);
34,288✔
2920
  }
2921
  code = colDataSetVal(pCol, pBlock->info.rows, pRes->buf, pRes->isNull || pResInfo->isNullRes);
8,808,751!
2922
  if (TSDB_CODE_SUCCESS != code) {
8,808,750!
2923
    return code;
×
2924
  }
2925

2926
  // handle selectivity
2927
  code = setSelectivityValue(pCtx, pBlock, &pRes->pos, pBlock->info.rows);
8,808,750✔
2928

2929
  return code;
8,808,756✔
2930
}
2931

2932
int32_t firstLastPartialFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
22,738,018✔
2933
  int32_t code = TSDB_CODE_SUCCESS;
22,738,018✔
2934

2935
  SResultRowEntryInfo* pEntryInfo = GET_RES_INFO(pCtx);
22,738,018✔
2936
  SFirstLastRes*       pRes = GET_ROWCELL_INTERBUF(pEntryInfo);
22,738,018✔
2937

2938
  int32_t resultBytes = getFirstLastInfoSize(pRes->bytes, pRes->pkBytes);
22,738,018✔
2939

2940
  // todo check for failure
2941
  char* res = taosMemoryCalloc(resultBytes + VARSTR_HEADER_SIZE, sizeof(char));
22,690,713!
2942
  if (NULL == res) {
22,871,108!
2943
    return terrno;
×
2944
  }
2945
  (void)memcpy(varDataVal(res), pRes, resultBytes);
22,871,108✔
2946

2947
  varDataSetLen(res, resultBytes);
22,871,108✔
2948

2949
  int32_t          slotId = pCtx->pExpr->base.resSchema.slotId;
22,871,108✔
2950
  SColumnInfoData* pCol = taosArrayGet(pBlock->pDataBlock, slotId);
22,871,108✔
2951
  if (NULL == pCol) {
22,841,489!
2952
    taosMemoryFree(res);
×
2953
    return TSDB_CODE_OUT_OF_RANGE;
×
2954
  }
2955

2956
  if (pEntryInfo->numOfRes == 0) {
22,855,043✔
2957
    colDataSetNULL(pCol, pBlock->info.rows);
2,369,352!
2958
    code = setSelectivityValue(pCtx, pBlock, &pRes->nullTuplePos, pBlock->info.rows);
2,369,352✔
2959
  } else {
2960
    code = colDataSetVal(pCol, pBlock->info.rows, res, false);
20,485,691✔
2961
    if (TSDB_CODE_SUCCESS != code) {
20,342,535!
2962
      taosMemoryFree(res);
×
2963
      return code;
×
2964
    }
2965
    code = setSelectivityValue(pCtx, pBlock, &pRes->pos, pBlock->info.rows);
20,342,535✔
2966
  }
2967
  taosMemoryFree(res);
22,727,554✔
2968
  return code;
22,974,527✔
2969
}
2970

2971
int32_t lastCombine(SqlFunctionCtx* pDestCtx, SqlFunctionCtx* pSourceCtx) {
3✔
2972
  SResultRowEntryInfo* pDResInfo = GET_RES_INFO(pDestCtx);
3✔
2973
  SFirstLastRes*       pDBuf = GET_ROWCELL_INTERBUF(pDResInfo);
3✔
2974
  int32_t              bytes = pDBuf->bytes;
3✔
2975

2976
  SResultRowEntryInfo* pSResInfo = GET_RES_INFO(pSourceCtx);
3✔
2977
  SFirstLastRes*       pSBuf = GET_ROWCELL_INTERBUF(pSResInfo);
3✔
2978

2979
  pDBuf->hasResult = firstLastTransferInfoImpl(pSBuf, pDBuf, false);
3✔
2980
  pDResInfo->numOfRes = TMAX(pDResInfo->numOfRes, pSResInfo->numOfRes);
3✔
2981
  pDResInfo->isNullRes &= pSResInfo->isNullRes;
3✔
2982
  return TSDB_CODE_SUCCESS;
3✔
2983
}
2984

2985
static int32_t doSaveLastrow(SqlFunctionCtx* pCtx, char* pData, int32_t rowIndex, int64_t cts, SFirstLastRes* pInfo) {
11,856✔
2986
  SInputColumnInfoData* pInput = &pCtx->input;
11,856✔
2987
  SColumnInfoData*      pInputCol = pInput->pData[0];
11,856✔
2988
  SColumnInfoData*      pkCol = pInput->pPrimaryKey;
11,856✔
2989

2990
  if (colDataIsNull_s(pInputCol, rowIndex)) {
23,712✔
2991
    pInfo->isNull = true;
2,132✔
2992
  } else {
2993
    pInfo->isNull = false;
9,724✔
2994

2995
    if (IS_VAR_DATA_TYPE(pInputCol->info.type)) {
9,724!
2996
      if (pInputCol->info.type == TSDB_DATA_TYPE_JSON) {
403!
2997
        pInfo->bytes = getJsonValueLen(pData);
×
2998
      } else {
2999
        pInfo->bytes = varDataTLen(pData);
403✔
3000
      }
3001
    }
3002

3003
    (void)memcpy(pInfo->buf, pData, pInfo->bytes);
9,724✔
3004
  }
3005

3006
  if (pCtx->hasPrimaryKey && !colDataIsNull_s(pkCol, rowIndex)) {
11,931!
3007
    char* pkData = colDataGetData(pkCol, rowIndex);
75!
3008
    if (IS_VAR_DATA_TYPE(pInfo->pkType)) {
75!
3009
      if (pInfo->pkType == TSDB_DATA_TYPE_JSON) {
12!
3010
        pInfo->pkBytes = getJsonValueLen(pkData);
×
3011
      } else {
3012
        pInfo->pkBytes = varDataTLen(pkData);
12✔
3013
      }
3014
    }
3015
    (void)memcpy(pInfo->buf + pInfo->bytes, pkData, pInfo->pkBytes);
75✔
3016
    pInfo->pkData = pInfo->buf + pInfo->bytes;
75✔
3017
  }
3018
  pInfo->ts = cts;
11,856✔
3019
  int32_t code = firstlastSaveTupleData(pCtx->pSrcBlock, rowIndex, pCtx, pInfo, false);
11,856✔
3020
  if (code != TSDB_CODE_SUCCESS) {
11,857!
3021
    return code;
×
3022
  }
3023

3024
  pInfo->hasResult = true;
11,857✔
3025

3026
  return TSDB_CODE_SUCCESS;
11,857✔
3027
}
3028

3029
int32_t lastRowFunction(SqlFunctionCtx* pCtx) {
27,006✔
3030
  int32_t numOfElems = 0;
27,006✔
3031

3032
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
27,006✔
3033
  SFirstLastRes*       pInfo = GET_ROWCELL_INTERBUF(pResInfo);
27,006✔
3034

3035
  SInputColumnInfoData* pInput = &pCtx->input;
27,006✔
3036
  SColumnInfoData*      pInputCol = pInput->pData[0];
27,006✔
3037

3038
  int32_t type = pInputCol->info.type;
27,006✔
3039
  int32_t bytes = pInputCol->info.bytes;
27,006✔
3040
  pInfo->bytes = bytes;
27,006✔
3041

3042
  if (IS_NULL_TYPE(type)) {
27,006✔
3043
    return TSDB_CODE_SUCCESS;
24✔
3044
  }
3045
  SColumnInfoData* pkCol = pInput->pPrimaryKey;
26,982✔
3046
  pInfo->pkType = -1;
26,982✔
3047
  __compar_fn_t pkCompareFn = NULL;
26,982✔
3048
  if (pCtx->hasPrimaryKey) {
26,982✔
3049
    pInfo->pkType = pkCol->info.type;
57✔
3050
    pInfo->pkBytes = pkCol->info.bytes;
57✔
3051
    pkCompareFn = getKeyComparFunc(pInfo->pkType, TSDB_ORDER_DESC);
57✔
3052
  }
3053
  TSKEY startKey = getRowPTs(pInput->pPTS, 0);
26,992!
3054
  TSKEY endKey = getRowPTs(pInput->pPTS, pInput->totalRows - 1);
26,992!
3055

3056
  if (pCtx->order == TSDB_ORDER_ASC && !pCtx->hasPrimaryKey) {
26,992!
3057
    for (int32_t i = pInput->numOfRows + pInput->startRowIndex - 1; i >= pInput->startRowIndex; --i) {
46,208!
3058
      bool  isNull = colDataIsNull(pInputCol, pInput->numOfRows, i, NULL);
23,127✔
3059
      char* data = isNull ? NULL : colDataGetData(pInputCol, i);
23,127!
3060
      TSKEY cts = getRowPTs(pInput->pPTS, i);
23,127!
3061
      numOfElems++;
23,127✔
3062

3063
      if (pResInfo->numOfRes == 0 || pInfo->ts < cts) {
23,127✔
3064
        int32_t code = doSaveLastrow(pCtx, data, i, cts, pInfo);
5,897✔
3065
        if (code != TSDB_CODE_SUCCESS) return code;
5,900!
3066
      }
3067

3068
      break;
23,130✔
3069
    }
3070
  } else if (!pCtx->hasPrimaryKey && pCtx->order == TSDB_ORDER_DESC) {
3,914✔
3071
    // the optimized version only valid if all tuples in one block are monotonious increasing or descreasing.
3072
    // this assumption is NOT always works if project operator exists in downstream.
3073
    for (int32_t i = pInput->startRowIndex; i < pInput->numOfRows + pInput->startRowIndex; ++i) {
7,699!
3074
      bool  isNull = colDataIsNull(pInputCol, pInput->numOfRows, i, NULL);
3,851✔
3075
      char* data = isNull ? NULL : colDataGetData(pInputCol, i);
3,851!
3076
      TSKEY cts = getRowPTs(pInput->pPTS, i);
3,851✔
3077
      numOfElems++;
3,851✔
3078

3079
      if (pResInfo->numOfRes == 0 || pInfo->ts < cts) {
3,851✔
3080
        int32_t code = doSaveLastrow(pCtx, data, i, cts, pInfo);
3,668✔
3081
        if (code != TSDB_CODE_SUCCESS) return code;
3,667!
3082
      }
3083
      break;
3,850✔
3084
    }
3085
  } else {
3086
    int64_t* pts = (int64_t*)pInput->pPTS->pData;
65✔
3087
    int      from = -1;
65✔
3088
    int32_t  i = -1;
65✔
3089
    while (funcInputGetNextRowIndex(pInput, from, false, &i, &from)) {
8,888✔
3090
      bool  isNull = colDataIsNull(pInputCol, pInput->numOfRows, i, NULL);
8,823✔
3091
      char* data = isNull ? NULL : colDataGetData(pInputCol, i);
8,823!
3092
      TSKEY cts = pts[i];
8,823✔
3093

3094
      numOfElems++;
8,823✔
3095
      char* pkData = NULL;
8,823✔
3096
      if (pCtx->hasPrimaryKey) {
8,823✔
3097
        pkData = colDataGetData(pkCol, i);
171!
3098
      }
3099
      if (pResInfo->numOfRes == 0 || pInfo->ts < cts ||
8,823✔
3100
          (pInfo->ts == pts[i] && pkCompareFn && pkCompareFn(pkData, pInfo->pkData) < 0)) {
8,628!
3101
        int32_t code = doSaveLastrow(pCtx, data, i, cts, pInfo);
201✔
3102
        if (code != TSDB_CODE_SUCCESS) {
201!
3103
          return code;
×
3104
        }
3105
        pResInfo->numOfRes = 1;
201✔
3106
      }
3107
    }
3108
  }
3109

3110
  SET_VAL(pResInfo, numOfElems, 1);
26,998!
3111
  return TSDB_CODE_SUCCESS;
26,998✔
3112
}
3113

3114
bool getDiffFuncEnv(SFunctionNode* UNUSED_PARAM(pFunc), SFuncExecEnv* pEnv) {
3,372✔
3115
  pEnv->calcMemSize = sizeof(SDiffInfo);
3,372✔
3116
  return true;
3,372✔
3117
}
3118

3119
int32_t diffFunctionSetup(SqlFunctionCtx* pCtx, SResultRowEntryInfo* pResInfo) {
226,899✔
3120
  if (pResInfo->initialized) {
226,899✔
3121
    return TSDB_CODE_SUCCESS;
192,065✔
3122
  }
3123
  if (TSDB_CODE_SUCCESS != functionSetup(pCtx, pResInfo)) {
34,834!
3124
    return TSDB_CODE_FUNC_SETUP_ERROR;
×
3125
  }
3126
  SDiffInfo* pDiffInfo = GET_ROWCELL_INTERBUF(pResInfo);
34,834✔
3127
  pDiffInfo->hasPrev = false;
34,834✔
3128
  pDiffInfo->isFirstRow = true;
34,834✔
3129
  pDiffInfo->prev.i64 = 0;
34,834✔
3130
  pDiffInfo->prevTs = -1;
34,834✔
3131
  if (pCtx->numOfParams > 1) {
34,834!
3132
    pDiffInfo->ignoreOption = pCtx->param[1].param.i;  // TODO set correct param
34,834✔
3133
  } else {
3134
    pDiffInfo->ignoreOption = 0;
×
3135
  }
3136
  return TSDB_CODE_SUCCESS;
34,834✔
3137
}
3138

3139
static int32_t doSetPrevVal(SDiffInfo* pDiffInfo, int32_t type, const char* pv, int64_t ts) {
33,811✔
3140
  switch (type) {
33,811!
3141
    case TSDB_DATA_TYPE_BOOL:
25✔
3142
      pDiffInfo->prev.i64 = *(bool*)pv ? 1 : 0;
25✔
3143
      break;
25✔
3144
    case TSDB_DATA_TYPE_UTINYINT:
286✔
3145
    case TSDB_DATA_TYPE_TINYINT:
3146
      pDiffInfo->prev.i64 = *(int8_t*)pv;
286✔
3147
      break;
286✔
3148
    case TSDB_DATA_TYPE_UINT:
32,292✔
3149
    case TSDB_DATA_TYPE_INT:
3150
      pDiffInfo->prev.i64 = *(int32_t*)pv;
32,292✔
3151
      break;
32,292✔
3152
    case TSDB_DATA_TYPE_USMALLINT:
295✔
3153
    case TSDB_DATA_TYPE_SMALLINT:
3154
      pDiffInfo->prev.i64 = *(int16_t*)pv;
295✔
3155
      break;
295✔
3156
    case TSDB_DATA_TYPE_TIMESTAMP:
285✔
3157
    case TSDB_DATA_TYPE_UBIGINT:
3158
    case TSDB_DATA_TYPE_BIGINT:
3159
      pDiffInfo->prev.i64 = *(int64_t*)pv;
285✔
3160
      break;
285✔
3161
    case TSDB_DATA_TYPE_FLOAT:
248✔
3162
      pDiffInfo->prev.d64 = *(float*)pv;
248✔
3163
      break;
248✔
3164
    case TSDB_DATA_TYPE_DOUBLE:
380✔
3165
      pDiffInfo->prev.d64 = *(double*)pv;
380✔
3166
      break;
380✔
3167
    default:
×
3168
      return TSDB_CODE_FUNC_FUNTION_PARA_TYPE;
×
3169
  }
3170
  pDiffInfo->prevTs = ts;
33,811✔
3171
  pDiffInfo->hasPrev = true;
33,811✔
3172
  return TSDB_CODE_SUCCESS;
33,811✔
3173
}
3174

3175
static bool diffIsNegtive(SDiffInfo* pDiffInfo, int32_t type, const char* pv) {
37,006✔
3176
  switch (type) {
37,006!
3177
    case TSDB_DATA_TYPE_UINT: {
×
3178
      int64_t v = *(uint32_t*)pv;
×
3179
      return v < pDiffInfo->prev.i64;
×
3180
    }
3181
    case TSDB_DATA_TYPE_INT: {
6,749✔
3182
      int64_t v = *(int32_t*)pv;
6,749✔
3183
      return v < pDiffInfo->prev.i64;
6,749✔
3184
    }
3185
    case TSDB_DATA_TYPE_BOOL: {
×
3186
      int64_t v = *(bool*)pv;
×
3187
      return v < pDiffInfo->prev.i64;
×
3188
    }
3189
    case TSDB_DATA_TYPE_UTINYINT: {
×
3190
      int64_t v = *(uint8_t*)pv;
×
3191
      return v < pDiffInfo->prev.i64;
×
3192
    }
3193
    case TSDB_DATA_TYPE_TINYINT: {
5,061✔
3194
      int64_t v = *(int8_t*)pv;
5,061✔
3195
      return v < pDiffInfo->prev.i64;
5,061✔
3196
    }
3197
    case TSDB_DATA_TYPE_USMALLINT: {
×
3198
      int64_t v = *(uint16_t*)pv;
×
3199
      return v < pDiffInfo->prev.i64;
×
3200
    }
3201
    case TSDB_DATA_TYPE_SMALLINT: {
6,526✔
3202
      int64_t v = *(int16_t*)pv;
6,526✔
3203
      return v < pDiffInfo->prev.i64;
6,526✔
3204
    }
3205
    case TSDB_DATA_TYPE_UBIGINT: {
24✔
3206
      uint64_t v = *(uint64_t*)pv;
24✔
3207
      return v < (uint64_t)pDiffInfo->prev.i64;
24✔
3208
    }
3209
    case TSDB_DATA_TYPE_TIMESTAMP:
7,395✔
3210
    case TSDB_DATA_TYPE_BIGINT: {
3211
      int64_t v = *(int64_t*)pv;
7,395✔
3212
      return v < pDiffInfo->prev.i64;
7,395✔
3213
    }
3214
    case TSDB_DATA_TYPE_FLOAT: {
4,781✔
3215
      float v = *(float*)pv;
4,781✔
3216
      return v < pDiffInfo->prev.d64;
4,781✔
3217
    }
3218
    case TSDB_DATA_TYPE_DOUBLE: {
6,470✔
3219
      double v = *(double*)pv;
6,470✔
3220
      return v < pDiffInfo->prev.d64;
6,470✔
3221
    }
3222
    default:
×
3223
      return false;
×
3224
  }
3225

3226
  return false;
3227
}
3228

3229
static void tryToSetInt64(SDiffInfo* pDiffInfo, int32_t type, SColumnInfoData* pOutput, int64_t v, int32_t pos) {
15,908,974✔
3230
  bool isNegative = v < pDiffInfo->prev.i64;
15,908,974✔
3231
  if (type == TSDB_DATA_TYPE_UBIGINT) {
15,908,974✔
3232
    isNegative = (uint64_t)v < (uint64_t)pDiffInfo->prev.i64;
453✔
3233
  }
3234
  int64_t delta = v - pDiffInfo->prev.i64;
15,908,974✔
3235
  if (isNegative && ignoreNegative(pDiffInfo->ignoreOption)) {
15,908,974✔
3236
    colDataSetNull_f_s(pOutput, pos);
12,781✔
3237
    pOutput->hasNull = true;
12,781✔
3238
  } else {
3239
    colDataSetInt64(pOutput, pos, &delta);
15,896,193✔
3240
  }
3241
  pDiffInfo->prev.i64 = v;
15,908,974✔
3242
}
15,908,974✔
3243

3244
static void tryToSetDouble(SDiffInfo* pDiffInfo, SColumnInfoData* pOutput, double v, int32_t pos) {
97,037✔
3245
  double delta = v - pDiffInfo->prev.d64;
97,037✔
3246
  if (delta < 0 && ignoreNegative(pDiffInfo->ignoreOption)) {
97,037✔
3247
    colDataSetNull_f_s(pOutput, pos);
5,620✔
3248
  } else {
3249
    colDataSetDouble(pOutput, pos, &delta);
91,417✔
3250
  }
3251
  pDiffInfo->prev.d64 = v;
97,037✔
3252
}
97,037✔
3253

3254
static int32_t doHandleDiff(SDiffInfo* pDiffInfo, int32_t type, const char* pv, SColumnInfoData* pOutput, int32_t pos,
16,006,452✔
3255
                            int64_t ts) {
3256
  if (!pDiffInfo->hasPrev) {
16,006,452✔
3257
    colDataSetNull_f_s(pOutput, pos);
441✔
3258
    return doSetPrevVal(pDiffInfo, type, pv, ts);
441✔
3259
  }
3260
  pDiffInfo->prevTs = ts;
16,006,011✔
3261
  switch (type) {
16,006,011!
3262
    case TSDB_DATA_TYPE_UINT: {
411✔
3263
      int64_t v = *(uint32_t*)pv;
411✔
3264
      tryToSetInt64(pDiffInfo, type, pOutput, v, pos);
411✔
3265
      break;
411✔
3266
    }
3267
    case TSDB_DATA_TYPE_INT: {
15,786,355✔
3268
      int64_t v = *(int32_t*)pv;
15,786,355✔
3269
      tryToSetInt64(pDiffInfo, type, pOutput, v, pos);
15,786,355✔
3270
      break;
15,786,355✔
3271
    }
3272
    case TSDB_DATA_TYPE_BOOL: {
10,560✔
3273
      int64_t v = *(bool*)pv;
10,560✔
3274
      tryToSetInt64(pDiffInfo, type, pOutput, v, pos);
10,560✔
3275
      break;
10,560✔
3276
    }
3277
    case TSDB_DATA_TYPE_UTINYINT: {
405✔
3278
      int64_t v = *(uint8_t*)pv;
405✔
3279
      tryToSetInt64(pDiffInfo, type, pOutput, v, pos);
405✔
3280
      break;
405✔
3281
    }
3282
    case TSDB_DATA_TYPE_TINYINT: {
33,634✔
3283
      int64_t v = *(int8_t*)pv;
33,634✔
3284
      tryToSetInt64(pDiffInfo, type, pOutput, v, pos);
33,634✔
3285
      break;
33,634✔
3286
    }
3287
    case TSDB_DATA_TYPE_USMALLINT: {
405✔
3288
      int64_t v = *(uint16_t*)pv;
405✔
3289
      tryToSetInt64(pDiffInfo, type, pOutput, v, pos);
405✔
3290
      break;
405✔
3291
    }
3292
    case TSDB_DATA_TYPE_SMALLINT: {
35,885✔
3293
      int64_t v = *(int16_t*)pv;
35,885✔
3294
      tryToSetInt64(pDiffInfo, type, pOutput, v, pos);
35,885✔
3295
      break;
35,885✔
3296
    }
3297
    case TSDB_DATA_TYPE_TIMESTAMP:
41,319✔
3298
    case TSDB_DATA_TYPE_UBIGINT:
3299
    case TSDB_DATA_TYPE_BIGINT: {
3300
      int64_t v = *(int64_t*)pv;
41,319✔
3301
      tryToSetInt64(pDiffInfo, type, pOutput, v, pos);
41,319✔
3302
      break;
41,319✔
3303
    }
3304
    case TSDB_DATA_TYPE_FLOAT: {
48,996✔
3305
      double v = *(float*)pv;
48,996✔
3306
      tryToSetDouble(pDiffInfo, pOutput, v, pos);
48,996✔
3307
      break;
48,996✔
3308
    }
3309
    case TSDB_DATA_TYPE_DOUBLE: {
48,041✔
3310
      double v = *(double*)pv;
48,041✔
3311
      tryToSetDouble(pDiffInfo, pOutput, v, pos);
48,041✔
3312
      break;
48,041✔
3313
    }
3314
    default:
×
3315
      return TSDB_CODE_FUNC_FUNTION_PARA_TYPE;
×
3316
  }
3317
  pDiffInfo->hasPrev = true;
16,006,011✔
3318
  return TSDB_CODE_SUCCESS;
16,006,011✔
3319
}
3320

3321
// TODO: the primary key compare can be skipped for ordered pk if knonwn before
3322
// TODO: for desc ordered, pk shall select the smallest one for one ts. if across block boundaries.
3323
bool funcInputGetNextRowIndex(SInputColumnInfoData* pInput, int32_t from, bool firstOccur, int32_t* pRowIndex,
198,610,072✔
3324
                              int32_t* nextFrom) {
3325
  if (pInput->pPrimaryKey == NULL) {
198,610,072✔
3326
    if (from == -1) {
98,656,763✔
3327
      from = pInput->startRowIndex;
36,428,599✔
3328
    } else if (from >= pInput->numOfRows + pInput->startRowIndex) {
62,228,164✔
3329
      return false;
36,146,827✔
3330
    }
3331
    *pRowIndex = from;
62,509,936✔
3332
    *nextFrom = from + 1;
62,509,936✔
3333
    return true;
62,509,936✔
3334
  } else {
3335
    if (from == -1) {
99,953,309✔
3336
      from = pInput->startRowIndex;
30,175✔
3337
    } else if (from >= pInput->numOfRows + pInput->startRowIndex) {
99,923,134✔
3338
      return false;
30,175✔
3339
    }
3340
    TSKEY*           tsList = (int64_t*)pInput->pPTS->pData;
99,923,134✔
3341
    SColumnInfoData* pkCol = pInput->pPrimaryKey;
99,923,134✔
3342
    int8_t           pkType = pkCol->info.type;
99,923,134✔
3343
    int32_t          order = (firstOccur) ? TSDB_ORDER_ASC : TSDB_ORDER_DESC;
99,923,134✔
3344
    __compar_fn_t    compareFunc = getKeyComparFunc(pkType, order);
99,923,134✔
3345
    int32_t          select = from;
100,000,517✔
3346
    char*            val = colDataGetData(pkCol, select);
100,000,517!
3347
    while (from < pInput->numOfRows + pInput->startRowIndex - 1 && tsList[from + 1] == tsList[from]) {
100,001,072✔
3348
      char* val1 = colDataGetData(pkCol, from + 1);
555!
3349
      if (compareFunc(val1, val) < 0) {
555!
3350
        select = from + 1;
×
3351
        val = val1;
×
3352
      }
3353
      from = from + 1;
555✔
3354
    }
3355
    *pRowIndex = select;
100,000,517✔
3356
    *nextFrom = from + 1;
100,000,517✔
3357
    return true;
100,000,517✔
3358
  }
3359
}
3360

3361
bool getForecastConfEnv(SFunctionNode* UNUSED_PARAM(pFunc), SFuncExecEnv* pEnv) {
×
3362
  pEnv->calcMemSize = sizeof(float);
×
3363
  return true;
×
3364
}
3365

3366
int32_t diffResultIsNull(SqlFunctionCtx* pCtx, SFuncInputRow* pRow) {
16,123,765✔
3367
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
16,123,765✔
3368
  SDiffInfo*           pDiffInfo = GET_ROWCELL_INTERBUF(pResInfo);
16,123,765✔
3369

3370
  if (pRow->isDataNull || !pDiffInfo->hasPrev) {
16,123,765✔
3371
    return true;
117,682✔
3372
  } else if (ignoreNegative(pDiffInfo->ignoreOption)) {
16,006,083✔
3373
    return diffIsNegtive(pDiffInfo, pCtx->input.pData[0]->info.type, pRow->pData);
37,006✔
3374
  }
3375
  return false;
15,969,077✔
3376
}
3377

3378
bool isFirstRow(SqlFunctionCtx* pCtx, SFuncInputRow* pRow) {
16,123,480✔
3379
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
16,123,480✔
3380
  SDiffInfo*           pDiffInfo = GET_ROWCELL_INTERBUF(pResInfo);
16,123,480✔
3381
  return pDiffInfo->isFirstRow;
16,123,480✔
3382
}
3383

3384
int32_t trySetPreVal(SqlFunctionCtx* pCtx, SFuncInputRow* pRow) {
34,954✔
3385
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
34,954✔
3386
  SDiffInfo*           pDiffInfo = GET_ROWCELL_INTERBUF(pResInfo);
34,954✔
3387
  pDiffInfo->isFirstRow = false;
34,954✔
3388
  if (pRow->isDataNull) {
34,954✔
3389
    return TSDB_CODE_SUCCESS;
1,584✔
3390
  }
3391

3392
  SInputColumnInfoData* pInput = &pCtx->input;
33,370✔
3393
  SColumnInfoData*      pInputCol = pInput->pData[0];
33,370✔
3394
  int8_t                inputType = pInputCol->info.type;
33,370✔
3395

3396
  char* pv = pRow->pData;
33,370✔
3397
  return doSetPrevVal(pDiffInfo, inputType, pv, pRow->ts);
33,370✔
3398
}
3399

3400
int32_t setDoDiffResult(SqlFunctionCtx* pCtx, SFuncInputRow* pRow, int32_t pos) {
16,088,811✔
3401
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
16,088,811✔
3402
  SDiffInfo*           pDiffInfo = GET_ROWCELL_INTERBUF(pResInfo);
16,088,811✔
3403

3404
  SInputColumnInfoData* pInput = &pCtx->input;
16,088,811✔
3405
  SColumnInfoData*      pInputCol = pInput->pData[0];
16,088,811✔
3406
  int8_t                inputType = pInputCol->info.type;
16,088,811✔
3407
  SColumnInfoData*      pOutput = (SColumnInfoData*)pCtx->pOutput;
16,088,811✔
3408
  int32_t               code = TSDB_CODE_SUCCESS;
16,088,811✔
3409
  if (pRow->isDataNull) {
16,088,811✔
3410
    colDataSetNull_f_s(pOutput, pos);
82,338✔
3411
    pOutput->hasNull = true;
82,338✔
3412

3413
    // handle selectivity
3414
    if (pCtx->subsidiaries.num > 0) {
82,338✔
3415
      code = appendSelectivityCols(pCtx, pRow->block, pRow->rowIndex, pos);
576✔
3416
      if (code != TSDB_CODE_SUCCESS) {
576!
3417
        return code;
×
3418
      }
3419
    }
3420
    return TSDB_CODE_SUCCESS;
82,338✔
3421
  }
3422

3423
  char* pv = pRow->pData;
16,006,473✔
3424

3425
  if (pRow->ts == pDiffInfo->prevTs) {
16,006,473✔
3426
    return TSDB_CODE_FUNC_DUP_TIMESTAMP;
21✔
3427
  }
3428
  code = doHandleDiff(pDiffInfo, inputType, pv, pOutput, pos, pRow->ts);
16,006,452✔
3429
  if (code != TSDB_CODE_SUCCESS) {
16,006,452!
3430
    return code;
×
3431
  }
3432
  // handle selectivity
3433
  if (pCtx->subsidiaries.num > 0) {
16,006,452✔
3434
    code = appendSelectivityCols(pCtx, pRow->block, pRow->rowIndex, pos);
15,702,031✔
3435
    if (code != TSDB_CODE_SUCCESS) {
15,702,031!
3436
      return code;
×
3437
    }
3438
  }
3439

3440
  return TSDB_CODE_SUCCESS;
16,006,452✔
3441
}
3442

3443
int32_t diffFunction(SqlFunctionCtx* pCtx) { return TSDB_CODE_SUCCESS; }
223,527✔
3444

3445
int32_t diffFunctionByRow(SArray* pCtxArray) {
223,371✔
3446
  int32_t code = TSDB_CODE_SUCCESS;
223,371✔
3447
  int     diffColNum = pCtxArray->size;
223,371✔
3448
  if (diffColNum == 0) {
223,371!
3449
    return TSDB_CODE_SUCCESS;
×
3450
  }
3451
  int32_t numOfElems = 0;
223,371✔
3452

3453
  SArray* pRows = taosArrayInit_s(sizeof(SFuncInputRow), diffColNum);
223,371✔
3454
  if (NULL == pRows) {
223,371!
3455
    return terrno;
×
3456
  }
3457

3458
  bool keepNull = false;
223,371✔
3459
  for (int i = 0; i < diffColNum; ++i) {
446,898✔
3460
    SqlFunctionCtx* pCtx = *(SqlFunctionCtx**)taosArrayGet(pCtxArray, i);
223,527✔
3461
    if (NULL == pCtx) {
223,527!
3462
      code = terrno;
×
3463
      goto _exit;
×
3464
    }
3465
    funcInputUpdate(pCtx);
223,527✔
3466
    SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
223,527✔
3467
    SDiffInfo*           pDiffInfo = GET_ROWCELL_INTERBUF(pResInfo);
223,527✔
3468
    if (!ignoreNull(pDiffInfo->ignoreOption)) {
223,527✔
3469
      keepNull = true;
223,404✔
3470
    }
3471
  }
3472

3473
  SqlFunctionCtx* pCtx0 = *(SqlFunctionCtx**)taosArrayGet(pCtxArray, 0);
223,371✔
3474
  SFuncInputRow*  pRow0 = (SFuncInputRow*)taosArrayGet(pRows, 0);
223,371✔
3475
  if (NULL == pCtx0 || NULL == pRow0) {
223,371!
3476
    code = terrno;
×
3477
    goto _exit;
×
3478
  }
3479
  int32_t startOffset = pCtx0->offset;
223,371✔
3480
  bool    result = false;
223,371✔
3481
  while (1) {
16,109,250✔
3482
    code = funcInputGetNextRow(pCtx0, pRow0, &result);
16,332,621✔
3483
    if (TSDB_CODE_SUCCESS != code) {
16,332,621!
3484
      goto _exit;
×
3485
    }
3486
    if (!result) {
16,332,621✔
3487
      break;
223,350✔
3488
    }
3489
    bool hasNotNullValue = !diffResultIsNull(pCtx0, pRow0);
16,109,271✔
3490
    for (int i = 1; i < diffColNum; ++i) {
16,123,765✔
3491
      SqlFunctionCtx* pCtx = *(SqlFunctionCtx**)taosArrayGet(pCtxArray, i);
14,494✔
3492
      SFuncInputRow*  pRow = (SFuncInputRow*)taosArrayGet(pRows, i);
14,494✔
3493
      if (NULL == pCtx || NULL == pRow) {
14,494!
3494
        code = terrno;
×
3495
        goto _exit;
×
3496
      }
3497
      code = funcInputGetNextRow(pCtx, pRow, &result);
14,494✔
3498
      if (TSDB_CODE_SUCCESS != code) {
14,494!
3499
        goto _exit;
×
3500
      }
3501
      if (!result) {
14,494!
3502
        // rows are not equal
3503
        code = TSDB_CODE_QRY_EXECUTOR_INTERNAL_ERROR;
×
3504
        goto _exit;
×
3505
      }
3506
      if (!diffResultIsNull(pCtx, pRow)) {
14,494✔
3507
        hasNotNullValue = true;
14,052✔
3508
      }
3509
    }
3510
    int32_t pos = startOffset + numOfElems;
16,109,271✔
3511

3512
    bool newRow = false;
16,109,271✔
3513
    for (int i = 0; i < diffColNum; ++i) {
32,233,015✔
3514
      SqlFunctionCtx* pCtx = *(SqlFunctionCtx**)taosArrayGet(pCtxArray, i);
16,123,765✔
3515
      SFuncInputRow*  pRow = (SFuncInputRow*)taosArrayGet(pRows, i);
16,123,765✔
3516
      if (NULL == pCtx || NULL == pRow) {
16,123,765!
3517
        code = terrno;
×
3518
        goto _exit;
×
3519
      }
3520
      if ((keepNull || hasNotNullValue) && !isFirstRow(pCtx, pRow)) {
16,123,765✔
3521
        code = setDoDiffResult(pCtx, pRow, pos);
16,088,811✔
3522
        if (code != TSDB_CODE_SUCCESS) {
16,088,811✔
3523
          goto _exit;
21✔
3524
        }
3525
        newRow = true;
16,088,790✔
3526
      } else {
3527
        code = trySetPreVal(pCtx, pRow);
34,954✔
3528
        if (code != TSDB_CODE_SUCCESS) {
34,954!
3529
          goto _exit;
×
3530
        }
3531
      }
3532
    }
3533
    if (newRow) ++numOfElems;
16,109,250✔
3534
  }
3535

3536
  for (int i = 0; i < diffColNum; ++i) {
446,853✔
3537
    SqlFunctionCtx* pCtx = *(SqlFunctionCtx**)taosArrayGet(pCtxArray, i);
223,503✔
3538
    if (NULL == pCtx) {
223,503!
3539
      code = terrno;
×
3540
      goto _exit;
×
3541
    }
3542
    SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
223,503✔
3543
    pResInfo->numOfRes = numOfElems;
223,503✔
3544
  }
3545

3546
_exit:
223,350✔
3547
  if (pRows) {
223,371!
3548
    taosArrayDestroy(pRows);
223,371✔
3549
    pRows = NULL;
223,371✔
3550
  }
3551
  return code;
223,371✔
3552
}
3553

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

3556
bool getTopBotFuncEnv(SFunctionNode* pFunc, SFuncExecEnv* pEnv) {
11,159✔
3557
  SValueNode* pkNode = (SValueNode*)nodesListGetNode(pFunc->pParameterList, 1);
11,159✔
3558
  pEnv->calcMemSize = sizeof(STopBotRes) + pkNode->datum.i * sizeof(STopBotResItem);
11,163✔
3559
  return true;
11,163✔
3560
}
3561

3562
int32_t topBotFunctionSetup(SqlFunctionCtx* pCtx, SResultRowEntryInfo* pResInfo) {
24,392✔
3563
  if (pResInfo->initialized) {
24,392!
3564
    return TSDB_CODE_SUCCESS;
×
3565
  }
3566
  if (TSDB_CODE_SUCCESS != functionSetup(pCtx, pResInfo)) {
24,392!
3567
    return TSDB_CODE_FUNC_SETUP_ERROR;
×
3568
  }
3569

3570
  STopBotRes*           pRes = GET_ROWCELL_INTERBUF(pResInfo);
24,396✔
3571
  SInputColumnInfoData* pInput = &pCtx->input;
24,396✔
3572

3573
  pRes->maxSize = pCtx->param[1].param.i;
24,396✔
3574

3575
  pRes->nullTupleSaved = false;
24,396✔
3576
  pRes->nullTuplePos.pageId = -1;
24,396✔
3577
  return TSDB_CODE_SUCCESS;
24,396✔
3578
}
3579

3580
static STopBotRes* getTopBotOutputInfo(SqlFunctionCtx* pCtx) {
462,200✔
3581
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
462,200✔
3582
  STopBotRes*          pRes = GET_ROWCELL_INTERBUF(pResInfo);
462,200✔
3583
  pRes->pItems = (STopBotResItem*)((char*)pRes + sizeof(STopBotRes));
462,200✔
3584

3585
  return pRes;
462,200✔
3586
}
3587

3588
static int32_t doAddIntoResult(SqlFunctionCtx* pCtx, void* pData, int32_t rowIndex, SSDataBlock* pSrcBlock,
3589
                               uint16_t type, uint64_t uid, SResultRowEntryInfo* pEntryInfo, bool isTopQuery);
3590

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

3593
int32_t topFunction(SqlFunctionCtx* pCtx) {
23,697✔
3594
  int32_t              numOfElems = 0;
23,697✔
3595
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
23,697✔
3596

3597
  SInputColumnInfoData* pInput = &pCtx->input;
23,697✔
3598
  SColumnInfoData*      pCol = pInput->pData[0];
23,697✔
3599

3600
  STopBotRes* pRes = getTopBotOutputInfo(pCtx);
23,697✔
3601
  pRes->type = pInput->pData[0]->info.type;
23,696✔
3602

3603
  int32_t start = pInput->startRowIndex;
23,696✔
3604
  for (int32_t i = start; i < pInput->numOfRows + start; ++i) {
370,025✔
3605
    if (pCol->hasNull && colDataIsNull_f(pCol->nullbitmap, i)) {
345,897✔
3606
      continue;
31,108✔
3607
    }
3608

3609
    numOfElems++;
314,789✔
3610
    char*   data = colDataGetData(pCol, i);
314,789!
3611
    int32_t code = doAddIntoResult(pCtx, data, i, pCtx->pSrcBlock, pRes->type, pInput->uid, pResInfo, true);
314,789✔
3612
    if (code != TSDB_CODE_SUCCESS) {
315,221!
3613
      return code;
×
3614
    }
3615
  }
3616

3617
  if (numOfElems == 0 && pCtx->subsidiaries.num > 0 && !pRes->nullTupleSaved) {
24,128✔
3618
    int32_t code = saveTupleData(pCtx, pInput->startRowIndex, pCtx->pSrcBlock, &pRes->nullTuplePos);
134✔
3619
    if (code != TSDB_CODE_SUCCESS) {
134!
3620
      return code;
×
3621
    }
3622
    pRes->nullTupleSaved = true;
134✔
3623
  }
3624
  return TSDB_CODE_SUCCESS;
24,128✔
3625
}
3626

3627
int32_t bottomFunction(SqlFunctionCtx* pCtx) {
3,065✔
3628
  int32_t              numOfElems = 0;
3,065✔
3629
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
3,065✔
3630

3631
  SInputColumnInfoData* pInput = &pCtx->input;
3,065✔
3632
  SColumnInfoData*      pCol = pInput->pData[0];
3,065✔
3633

3634
  STopBotRes* pRes = getTopBotOutputInfo(pCtx);
3,065✔
3635
  pRes->type = pInput->pData[0]->info.type;
3,064✔
3636

3637
  int32_t start = pInput->startRowIndex;
3,064✔
3638
  for (int32_t i = start; i < pInput->numOfRows + start; ++i) {
132,078✔
3639
    if (pCol->hasNull && colDataIsNull_f(pCol->nullbitmap, i)) {
129,151✔
3640
      continue;
31,846✔
3641
    }
3642

3643
    numOfElems++;
97,305✔
3644
    char*   data = colDataGetData(pCol, i);
97,305!
3645
    int32_t code = doAddIntoResult(pCtx, data, i, pCtx->pSrcBlock, pRes->type, pInput->uid, pResInfo, false);
97,305✔
3646
    if (code != TSDB_CODE_SUCCESS) {
97,168!
3647
      return code;
×
3648
    }
3649
  }
3650

3651
  if (numOfElems == 0 && pCtx->subsidiaries.num > 0 && !pRes->nullTupleSaved) {
2,927✔
3652
    int32_t code = saveTupleData(pCtx, pInput->startRowIndex, pCtx->pSrcBlock, &pRes->nullTuplePos);
91✔
3653
    if (code != TSDB_CODE_SUCCESS) {
91!
3654
      return code;
×
3655
    }
3656
    pRes->nullTupleSaved = true;
91✔
3657
  }
3658

3659
  return TSDB_CODE_SUCCESS;
2,927✔
3660
}
3661

3662
static int32_t topBotResComparFn(const void* p1, const void* p2, const void* param) {
1,476,267✔
3663
  uint16_t type = *(uint16_t*)param;
1,476,267✔
3664

3665
  STopBotResItem* val1 = (STopBotResItem*)p1;
1,476,267✔
3666
  STopBotResItem* val2 = (STopBotResItem*)p2;
1,476,267✔
3667

3668
  if (IS_SIGNED_NUMERIC_TYPE(type)) {
1,476,267!
3669
    if (val1->v.i == val2->v.i) {
801,089✔
3670
      return 0;
168,641✔
3671
    }
3672

3673
    return (val1->v.i > val2->v.i) ? 1 : -1;
632,448✔
3674
  } else if (IS_UNSIGNED_NUMERIC_TYPE(type)) {
675,178✔
3675
    if (val1->v.u == val2->v.u) {
479,743✔
3676
      return 0;
105,842✔
3677
    }
3678

3679
    return (val1->v.u > val2->v.u) ? 1 : -1;
373,901✔
3680
  } else if (TSDB_DATA_TYPE_FLOAT == type) {
195,435✔
3681
    if (val1->v.f == val2->v.f) {
19,290✔
3682
      return 0;
63✔
3683
    }
3684

3685
    return (val1->v.f > val2->v.f) ? 1 : -1;
19,227✔
3686
  }
3687

3688
  if (val1->v.d == val2->v.d) {
176,145✔
3689
    return 0;
11✔
3690
  }
3691

3692
  return (val1->v.d > val2->v.d) ? 1 : -1;
176,134✔
3693
}
3694

3695
int32_t doAddIntoResult(SqlFunctionCtx* pCtx, void* pData, int32_t rowIndex, SSDataBlock* pSrcBlock, uint16_t type,
411,589✔
3696
                        uint64_t uid, SResultRowEntryInfo* pEntryInfo, bool isTopQuery) {
3697
  STopBotRes* pRes = getTopBotOutputInfo(pCtx);
411,589✔
3698
  int32_t     code = TSDB_CODE_SUCCESS;
411,632✔
3699

3700
  SVariant val = {0};
411,632✔
3701
  TAOS_CHECK_RETURN(taosVariantCreateFromBinary(&val, pData, tDataTypes[type].bytes, type));
411,632!
3702

3703
  STopBotResItem* pItems = pRes->pItems;
412,018✔
3704

3705
  // not full yet
3706
  if (pEntryInfo->numOfRes < pRes->maxSize) {
412,018✔
3707
    STopBotResItem* pItem = &pItems[pEntryInfo->numOfRes];
111,174✔
3708
    pItem->v = val;
111,174✔
3709
    pItem->uid = uid;
111,174✔
3710

3711
    // save the data of this tuple
3712
    if (pCtx->subsidiaries.num > 0) {
111,174✔
3713
      code = saveTupleData(pCtx, rowIndex, pSrcBlock, &pItem->tuplePos);
44,921✔
3714
      if (code != TSDB_CODE_SUCCESS) {
44,875!
3715
        return code;
×
3716
      }
3717
    }
3718
#ifdef BUF_PAGE_DEBUG
3719
    qDebug("page_saveTuple i:%d, item:%p,pageId:%d, offset:%d\n", pEntryInfo->numOfRes, pItem, pItem->tuplePos.pageId,
3720
           pItem->tuplePos.offset);
3721
#endif
3722
    // allocate the buffer and keep the data of this row into the new allocated buffer
3723
    pEntryInfo->numOfRes++;
111,128✔
3724
    code = taosheapsort((void*)pItems, sizeof(STopBotResItem), pEntryInfo->numOfRes, (const void*)&type,
111,128✔
3725
                        topBotResComparFn, !isTopQuery);
111,128✔
3726
    if (code != TSDB_CODE_SUCCESS) {
111,417!
3727
      return code;
×
3728
    }
3729
  } else {  // replace the minimum value in the result
3730
    if ((isTopQuery && ((IS_SIGNED_NUMERIC_TYPE(type) && val.i > pItems[0].v.i) ||
300,844!
3731
                        (IS_UNSIGNED_NUMERIC_TYPE(type) && val.u > pItems[0].v.u) ||
157,385✔
3732
                        (TSDB_DATA_TYPE_FLOAT == type && val.f > pItems[0].v.f) ||
102,848✔
3733
                        (TSDB_DATA_TYPE_DOUBLE == type && val.d > pItems[0].v.d))) ||
102,352✔
3734
        (!isTopQuery && ((IS_SIGNED_NUMERIC_TYPE(type) && val.i < pItems[0].v.i) ||
163,002!
3735
                         (IS_UNSIGNED_NUMERIC_TYPE(type) && val.u < pItems[0].v.u) ||
74,224!
3736
                         (TSDB_DATA_TYPE_FLOAT == type && val.f < pItems[0].v.f) ||
73,278✔
3737
                         (TSDB_DATA_TYPE_DOUBLE == type && val.d < pItems[0].v.d)))) {
72,286✔
3738
      // replace the old data and the coresponding tuple data
3739
      STopBotResItem* pItem = &pItems[0];
145,753✔
3740
      pItem->v = val;
145,753✔
3741
      pItem->uid = uid;
145,753✔
3742

3743
      // save the data of this tuple by over writing the old data
3744
      if (pCtx->subsidiaries.num > 0) {
145,753✔
3745
        code = updateTupleData(pCtx, rowIndex, pSrcBlock, &pItem->tuplePos);
115,726✔
3746
        if (code != TSDB_CODE_SUCCESS) {
115,397!
3747
          return code;
×
3748
        }
3749
      }
3750
#ifdef BUF_PAGE_DEBUG
3751
      qDebug("page_copyTuple pageId:%d, offset:%d", pItem->tuplePos.pageId, pItem->tuplePos.offset);
3752
#endif
3753
      code = taosheapadjust((void*)pItems, sizeof(STopBotResItem), 0, pEntryInfo->numOfRes - 1, (const void*)&type,
145,424✔
3754
                            topBotResComparFn, NULL, !isTopQuery);
145,424✔
3755
      if (code != TSDB_CODE_SUCCESS) {
145,951!
3756
        return code;
×
3757
      }
3758
    }
3759
  }
3760

3761
  return TSDB_CODE_SUCCESS;
412,459✔
3762
}
3763

3764
/*
3765
 * +------------------------------------+--------------+--------------+
3766
 * |            null bitmap             |              |              |
3767
 * |(n columns, one bit for each column)| src column #1| src column #2|
3768
 * +------------------------------------+--------------+--------------+
3769
 */
3770
int32_t serializeTupleData(const SSDataBlock* pSrcBlock, int32_t rowIndex, SSubsidiaryResInfo* pSubsidiaryies,
399,447✔
3771
                           char* buf, char** res) {
3772
  char* nullList = buf;
399,447✔
3773
  char* pStart = (char*)(nullList + sizeof(bool) * pSubsidiaryies->num);
399,447✔
3774

3775
  int32_t offset = 0;
399,447✔
3776
  for (int32_t i = 0; i < pSubsidiaryies->num; ++i) {
841,543✔
3777
    SqlFunctionCtx* pc = pSubsidiaryies->pCtx[i];
442,091✔
3778

3779
    // group_key function has its own process function
3780
    // do not process there
3781
    if (fmIsGroupKeyFunc(pc->functionId)) {
442,091✔
3782
      continue;
36,729✔
3783
    }
3784

3785
    SFunctParam* pFuncParam = &pc->pExpr->base.pParam[0];
405,381✔
3786
    int32_t      srcSlotId = pFuncParam->pCol->slotId;
405,381✔
3787

3788
    SColumnInfoData* pCol = taosArrayGet(pSrcBlock->pDataBlock, srcSlotId);
405,381✔
3789
    if (NULL == pCol) {
405,367!
3790
      return TSDB_CODE_OUT_OF_RANGE;
×
3791
    }
3792
    if ((nullList[i] = colDataIsNull_s(pCol, rowIndex)) == true) {
810,734✔
3793
      offset += pCol->info.bytes;
247✔
3794
      continue;
247✔
3795
    }
3796

3797
    char* p = colDataGetData(pCol, rowIndex);
405,120!
3798
    if (IS_VAR_DATA_TYPE(pCol->info.type)) {
405,120!
3799
      (void)memcpy(pStart + offset, p, (pCol->info.type == TSDB_DATA_TYPE_JSON) ? getJsonValueLen(p) : varDataTLen(p));
31,968!
3800
    } else {
3801
      (void)memcpy(pStart + offset, p, pCol->info.bytes);
373,152✔
3802
    }
3803

3804
    offset += pCol->info.bytes;
405,120✔
3805
  }
3806

3807
  *res = buf;
399,452✔
3808
  return TSDB_CODE_SUCCESS;
399,452✔
3809
}
3810

3811
static int32_t doSaveTupleData(SSerializeDataHandle* pHandle, const void* pBuf, size_t length, SWinKey* key,
594,351✔
3812
                               STuplePos* pPos, SFunctionStateStore* pStore) {
3813
  STuplePos p = {0};
594,351✔
3814
  if (pHandle->pBuf != NULL) {
594,351✔
3815
    SFilePage* pPage = NULL;
529,091✔
3816

3817
    if (pHandle->currentPage == -1) {
529,091✔
3818
      pPage = getNewBufPage(pHandle->pBuf, &pHandle->currentPage);
19,008✔
3819
      if (pPage == NULL) {
19,010!
3820
        return terrno;
×
3821
      }
3822
      pPage->num = sizeof(SFilePage);
19,010✔
3823
    } else {
3824
      pPage = getBufPage(pHandle->pBuf, pHandle->currentPage);
510,083✔
3825
      if (pPage == NULL) {
509,326!
3826
        return terrno;
×
3827
      }
3828
      if (pPage->num + length > getBufPageSize(pHandle->pBuf)) {
509,326✔
3829
        // current page is all used, let's prepare a new buffer page
3830
        releaseBufPage(pHandle->pBuf, pPage);
202✔
3831
        pPage = getNewBufPage(pHandle->pBuf, &pHandle->currentPage);
202✔
3832
        if (pPage == NULL) {
202!
3833
          return terrno;
×
3834
        }
3835
        pPage->num = sizeof(SFilePage);
202✔
3836
      }
3837
    }
3838

3839
    p = (STuplePos){.pageId = pHandle->currentPage, .offset = pPage->num};
528,232✔
3840
    (void)memcpy(pPage->data + pPage->num, pBuf, length);
528,232✔
3841

3842
    pPage->num += length;
528,232✔
3843
    setBufPageDirty(pPage, true);
528,232✔
3844
    releaseBufPage(pHandle->pBuf, pPage);
527,842✔
3845
  } else {  // other tuple save policy
3846
    if (pStore->streamStateFuncPut(pHandle->pState, key, pBuf, length) >= 0) {
65,260!
3847
      p.streamTupleKey = *key;
65,254✔
3848
    }
3849
  }
3850

3851
  *pPos = p;
592,494✔
3852
  return TSDB_CODE_SUCCESS;
592,494✔
3853
}
3854

3855
int32_t saveTupleData(SqlFunctionCtx* pCtx, int32_t rowIndex, const SSDataBlock* pSrcBlock, STuplePos* pPos) {
149,957✔
3856
  int32_t code = prepareBuf(pCtx);
149,957✔
3857
  if (TSDB_CODE_SUCCESS != code) {
149,960!
3858
    return code;
×
3859
  }
3860

3861
  SWinKey key = {0};
149,960✔
3862
  if (pCtx->saveHandle.pBuf == NULL) {
149,960✔
3863
    SColumnInfoData* pColInfo = taosArrayGet(pSrcBlock->pDataBlock, pCtx->saveHandle.pState->tsIndex);
65,256✔
3864
    if (NULL == pColInfo) {
65,256!
3865
      return TSDB_CODE_OUT_OF_RANGE;
×
3866
    }
3867
    if (pColInfo->info.type != TSDB_DATA_TYPE_TIMESTAMP) {
65,256!
3868
      return TSDB_CODE_FUNC_FUNTION_PARA_TYPE;
×
3869
    }
3870
    key.groupId = pSrcBlock->info.id.groupId;
65,256✔
3871
    key.ts = *(int64_t*)colDataGetData(pColInfo, rowIndex);
65,256!
3872
  }
3873

3874
  char* buf = NULL;
149,960✔
3875
  code = serializeTupleData(pSrcBlock, rowIndex, &pCtx->subsidiaries, pCtx->subsidiaries.buf, &buf);
149,960✔
3876
  if (TSDB_CODE_SUCCESS != code) {
149,945!
3877
    return code;
×
3878
  }
3879
  return doSaveTupleData(&pCtx->saveHandle, buf, pCtx->subsidiaries.rowLen, &key, pPos, pCtx->pStore);
149,945✔
3880
}
3881

3882
static int32_t doUpdateTupleData(SSerializeDataHandle* pHandle, const void* pBuf, size_t length, STuplePos* pPos,
249,542✔
3883
                                 SFunctionStateStore* pStore) {
3884
  if (pHandle->pBuf != NULL) {
249,542✔
3885
    SFilePage* pPage = getBufPage(pHandle->pBuf, pPos->pageId);
133,168✔
3886
    if (pPage == NULL) {
133,108!
3887
      return terrno;
×
3888
    }
3889
    (void)memcpy(pPage->data + pPos->offset, pBuf, length);
133,108✔
3890
    setBufPageDirty(pPage, true);
133,108✔
3891
    releaseBufPage(pHandle->pBuf, pPage);
133,073✔
3892
  } else {
3893
    int32_t code = pStore->streamStateFuncPut(pHandle->pState, &pPos->streamTupleKey, pBuf, length);
116,374✔
3894
    if (TSDB_CODE_SUCCESS != code) {
116,386!
3895
      return code;
×
3896
    }
3897
  }
3898

3899
  return TSDB_CODE_SUCCESS;
249,294✔
3900
}
3901

3902
int32_t updateTupleData(SqlFunctionCtx* pCtx, int32_t rowIndex, const SSDataBlock* pSrcBlock, STuplePos* pPos) {
249,607✔
3903
  int32_t code = prepareBuf(pCtx);
249,607✔
3904
  if (TSDB_CODE_SUCCESS != code) {
249,595!
3905
    return code;
×
3906
  }
3907

3908
  char* buf = NULL;
249,595✔
3909
  code = serializeTupleData(pSrcBlock, rowIndex, &pCtx->subsidiaries, pCtx->subsidiaries.buf, &buf);
249,595✔
3910
  if (TSDB_CODE_SUCCESS != code) {
249,543!
3911
    return code;
×
3912
  }
3913
  return doUpdateTupleData(&pCtx->saveHandle, buf, pCtx->subsidiaries.rowLen, pPos, pCtx->pStore);
249,543✔
3914
}
3915

3916
static int32_t doLoadTupleData(SSerializeDataHandle* pHandle, const STuplePos* pPos, SFunctionStateStore* pStore,
145,399✔
3917
                               char** value) {
3918
  if (pHandle->pBuf != NULL) {
145,399✔
3919
    SFilePage* pPage = getBufPage(pHandle->pBuf, pPos->pageId);
79,572✔
3920
    if (pPage == NULL) {
79,577!
3921
      *value = NULL;
×
3922
      return terrno;
×
3923
    }
3924
    *value = pPage->data + pPos->offset;
79,577✔
3925
    releaseBufPage(pHandle->pBuf, pPage);
79,577✔
3926
    return TSDB_CODE_SUCCESS;
79,576✔
3927
  } else {
3928
    *value = NULL;
65,827✔
3929
    int32_t vLen;
3930
    int32_t code = pStore->streamStateFuncGet(pHandle->pState, &pPos->streamTupleKey, (void**)(value), &vLen);
65,827✔
3931
    if (TSDB_CODE_SUCCESS != code) {
65,822!
3932
      return code;
×
3933
    }
3934
    return TSDB_CODE_SUCCESS;
65,822✔
3935
  }
3936
}
3937

3938
int32_t loadTupleData(SqlFunctionCtx* pCtx, const STuplePos* pPos, char** value) {
145,410✔
3939
  return doLoadTupleData(&pCtx->saveHandle, pPos, pCtx->pStore, value);
145,410✔
3940
}
3941

3942
int32_t topBotFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
24,407✔
3943
  int32_t code = TSDB_CODE_SUCCESS;
24,407✔
3944

3945
  SResultRowEntryInfo* pEntryInfo = GET_RES_INFO(pCtx);
24,407✔
3946
  STopBotRes*          pRes = getTopBotOutputInfo(pCtx);
24,407✔
3947

3948
  int16_t type = pCtx->pExpr->base.resSchema.type;
24,407✔
3949
  int32_t slotId = pCtx->pExpr->base.resSchema.slotId;
24,407✔
3950

3951
  SColumnInfoData* pCol = taosArrayGet(pBlock->pDataBlock, slotId);
24,407✔
3952
  if (NULL == pCol) {
24,405!
3953
    return TSDB_CODE_OUT_OF_RANGE;
×
3954
  }
3955

3956
  // todo assign the tag value and the corresponding row data
3957
  int32_t currentRow = pBlock->info.rows;
24,405✔
3958
  if (pEntryInfo->numOfRes <= 0) {
24,405✔
3959
    colDataSetNULL(pCol, currentRow);
617!
3960
    code = setSelectivityValue(pCtx, pBlock, &pRes->nullTuplePos, currentRow);
617✔
3961
    return code;
617✔
3962
  }
3963
  for (int32_t i = 0; i < pEntryInfo->numOfRes; ++i) {
135,208✔
3964
    STopBotResItem* pItem = &pRes->pItems[i];
111,417✔
3965
    code = colDataSetVal(pCol, currentRow, (const char*)&pItem->v.i, false);
111,417✔
3966
    if (TSDB_CODE_SUCCESS != code) {
111,399!
3967
      return code;
×
3968
    }
3969
#ifdef BUF_PAGE_DEBUG
3970
    qDebug("page_finalize i:%d,item:%p,pageId:%d, offset:%d\n", i, pItem, pItem->tuplePos.pageId,
3971
           pItem->tuplePos.offset);
3972
#endif
3973
    code = setSelectivityValue(pCtx, pBlock, &pRes->pItems[i].tuplePos, currentRow);
111,399✔
3974
    if (TSDB_CODE_SUCCESS != code) {
111,420!
3975
      return code;
×
3976
    }
3977
    currentRow += 1;
111,420✔
3978
  }
3979

3980
  return code;
23,791✔
3981
}
3982

3983
int32_t addResult(SqlFunctionCtx* pCtx, STopBotResItem* pSourceItem, int16_t type, bool isTopQuery) {
×
3984
  SResultRowEntryInfo* pEntryInfo = GET_RES_INFO(pCtx);
×
3985
  STopBotRes*          pRes = getTopBotOutputInfo(pCtx);
×
3986
  STopBotResItem*      pItems = pRes->pItems;
×
3987
  int32_t              code = TSDB_CODE_SUCCESS;
×
3988

3989
  // not full yet
3990
  if (pEntryInfo->numOfRes < pRes->maxSize) {
×
3991
    STopBotResItem* pItem = &pItems[pEntryInfo->numOfRes];
×
3992
    pItem->v = pSourceItem->v;
×
3993
    pItem->uid = pSourceItem->uid;
×
3994
    pItem->tuplePos.pageId = -1;
×
3995
    replaceTupleData(&pItem->tuplePos, &pSourceItem->tuplePos);
×
3996
    pEntryInfo->numOfRes++;
×
3997
    code = taosheapsort((void*)pItems, sizeof(STopBotResItem), pEntryInfo->numOfRes, (const void*)&type,
×
3998
                        topBotResComparFn, !isTopQuery);
×
3999
    if (TSDB_CODE_SUCCESS != code) {
×
4000
      return code;
×
4001
    }
4002
  } else {  // replace the minimum value in the result
4003
    if ((isTopQuery && ((IS_SIGNED_NUMERIC_TYPE(type) && pSourceItem->v.i > pItems[0].v.i) ||
×
4004
                        (IS_UNSIGNED_NUMERIC_TYPE(type) && pSourceItem->v.u > pItems[0].v.u) ||
×
4005
                        (TSDB_DATA_TYPE_FLOAT == type && pSourceItem->v.f > pItems[0].v.f) ||
×
4006
                        (TSDB_DATA_TYPE_DOUBLE == type && pSourceItem->v.d > pItems[0].v.d))) ||
×
4007
        (!isTopQuery && ((IS_SIGNED_NUMERIC_TYPE(type) && pSourceItem->v.i < pItems[0].v.i) ||
×
4008
                         (IS_UNSIGNED_NUMERIC_TYPE(type) && pSourceItem->v.u < pItems[0].v.u) ||
×
4009
                         (TSDB_DATA_TYPE_FLOAT == type && pSourceItem->v.f < pItems[0].v.f) ||
×
4010
                         (TSDB_DATA_TYPE_DOUBLE == type && pSourceItem->v.d < pItems[0].v.d)))) {
×
4011
      // replace the old data and the coresponding tuple data
4012
      STopBotResItem* pItem = &pItems[0];
×
4013
      pItem->v = pSourceItem->v;
×
4014
      pItem->uid = pSourceItem->uid;
×
4015

4016
      // save the data of this tuple by over writing the old data
4017
      replaceTupleData(&pItem->tuplePos, &pSourceItem->tuplePos);
×
4018
      code = taosheapadjust((void*)pItems, sizeof(STopBotResItem), 0, pEntryInfo->numOfRes - 1, (const void*)&type,
×
4019
                            topBotResComparFn, NULL, !isTopQuery);
×
4020
      if (TSDB_CODE_SUCCESS != code) {
×
4021
        return code;
×
4022
      }
4023
    }
4024
  }
4025
  return code;
×
4026
}
4027

4028
int32_t topCombine(SqlFunctionCtx* pDestCtx, SqlFunctionCtx* pSourceCtx) {
×
4029
  SResultRowEntryInfo* pSResInfo = GET_RES_INFO(pSourceCtx);
×
4030
  STopBotRes*          pSBuf = getTopBotOutputInfo(pSourceCtx);
×
4031
  int16_t              type = pSBuf->type;
×
4032
  int32_t              code = TSDB_CODE_SUCCESS;
×
4033
  for (int32_t i = 0; i < pSResInfo->numOfRes; i++) {
×
4034
    code = addResult(pDestCtx, pSBuf->pItems + i, type, true);
×
4035
    if (TSDB_CODE_SUCCESS != code) {
×
4036
      return code;
×
4037
    }
4038
  }
4039
  return TSDB_CODE_SUCCESS;
×
4040
}
4041

4042
int32_t bottomCombine(SqlFunctionCtx* pDestCtx, SqlFunctionCtx* pSourceCtx) {
×
4043
  SResultRowEntryInfo* pSResInfo = GET_RES_INFO(pSourceCtx);
×
4044
  STopBotRes*          pSBuf = getTopBotOutputInfo(pSourceCtx);
×
4045
  int16_t              type = pSBuf->type;
×
4046
  int32_t              code = TSDB_CODE_SUCCESS;
×
4047
  for (int32_t i = 0; i < pSResInfo->numOfRes; i++) {
×
4048
    code = addResult(pDestCtx, pSBuf->pItems + i, type, false);
×
4049
    if (TSDB_CODE_SUCCESS != code) {
×
4050
      return code;
×
4051
    }
4052
  }
4053
  return TSDB_CODE_SUCCESS;
×
4054
}
4055

4056
int32_t getSpreadInfoSize() { return (int32_t)sizeof(SSpreadInfo); }
23,839✔
4057

4058
bool getSpreadFuncEnv(SFunctionNode* UNUSED_PARAM(pFunc), SFuncExecEnv* pEnv) {
57,113✔
4059
  pEnv->calcMemSize = sizeof(SSpreadInfo);
57,113✔
4060
  return true;
57,113✔
4061
}
4062

4063
int32_t spreadFunctionSetup(SqlFunctionCtx* pCtx, SResultRowEntryInfo* pResultInfo) {
260,662✔
4064
  if (pResultInfo->initialized) {
260,662!
4065
    return TSDB_CODE_SUCCESS;
×
4066
  }
4067
  if (TSDB_CODE_SUCCESS != functionSetup(pCtx, pResultInfo)) {
260,662!
4068
    return TSDB_CODE_FUNC_SETUP_ERROR;
×
4069
  }
4070

4071
  SSpreadInfo* pInfo = GET_ROWCELL_INTERBUF(pResultInfo);
260,696✔
4072
  SET_DOUBLE_VAL(&pInfo->min, DBL_MAX);
260,696✔
4073
  SET_DOUBLE_VAL(&pInfo->max, -DBL_MAX);
260,696✔
4074
  pInfo->hasResult = false;
260,696✔
4075
  return TSDB_CODE_SUCCESS;
260,696✔
4076
}
4077

4078
int32_t spreadFunction(SqlFunctionCtx* pCtx) {
272,982✔
4079
  int32_t numOfElems = 0;
272,982✔
4080

4081
  // Only the pre-computing information loaded and actual data does not loaded
4082
  SInputColumnInfoData* pInput = &pCtx->input;
272,982✔
4083
  SColumnDataAgg*       pAgg = pInput->pColumnDataAgg[0];
272,982✔
4084
  int32_t               type = pInput->pData[0]->info.type;
272,982✔
4085

4086
  SSpreadInfo* pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
272,982✔
4087

4088
  if (pInput->colDataSMAIsSet) {
272,982!
4089
    numOfElems = pInput->numOfRows - pAgg->numOfNull;
×
4090
    if (numOfElems == 0) {
×
4091
      goto _spread_over;
×
4092
    }
4093
    double tmin = 0.0, tmax = 0.0;
×
4094
    if (IS_SIGNED_NUMERIC_TYPE(type) || IS_TIMESTAMP_TYPE(type)) {
×
4095
      tmin = (double)GET_INT64_VAL(&pAgg->min);
×
4096
      tmax = (double)GET_INT64_VAL(&pAgg->max);
×
4097
    } else if (IS_FLOAT_TYPE(type)) {
×
4098
      tmin = GET_DOUBLE_VAL(&pAgg->min);
×
4099
      tmax = GET_DOUBLE_VAL(&pAgg->max);
×
4100
    } else if (IS_UNSIGNED_NUMERIC_TYPE(type)) {
×
4101
      tmin = (double)GET_UINT64_VAL(&pAgg->min);
×
4102
      tmax = (double)GET_UINT64_VAL(&pAgg->max);
×
4103
    }
4104

4105
    if (GET_DOUBLE_VAL(&pInfo->min) > tmin) {
×
4106
      SET_DOUBLE_VAL(&pInfo->min, tmin);
×
4107
    }
4108

4109
    if (GET_DOUBLE_VAL(&pInfo->max) < tmax) {
×
4110
      SET_DOUBLE_VAL(&pInfo->max, tmax);
×
4111
    }
4112

4113
  } else {  // computing based on the true data block
4114
    SColumnInfoData* pCol = pInput->pData[0];
272,982✔
4115

4116
    int32_t start = pInput->startRowIndex;
272,982✔
4117
    // check the valid data one by one
4118
    for (int32_t i = start; i < pInput->numOfRows + start; ++i) {
5,424,431✔
4119
      if (colDataIsNull_f(pCol->nullbitmap, i)) {
5,151,449✔
4120
        continue;
1,622,437✔
4121
      }
4122

4123
      char* data = colDataGetData(pCol, i);
3,529,012!
4124

4125
      double v = 0;
3,529,012✔
4126
      GET_TYPED_DATA(v, double, type, data);
3,529,012!
4127
      if (v < GET_DOUBLE_VAL(&pInfo->min)) {
3,529,012✔
4128
        SET_DOUBLE_VAL(&pInfo->min, v);
241,092✔
4129
      }
4130

4131
      if (v > GET_DOUBLE_VAL(&pInfo->max)) {
3,529,012✔
4132
        SET_DOUBLE_VAL(&pInfo->max, v);
501,076✔
4133
      }
4134

4135
      numOfElems += 1;
3,529,012✔
4136
    }
4137
  }
4138

4139
_spread_over:
272,982✔
4140
  // data in the check operation are all null, not output
4141
  SET_VAL(GET_RES_INFO(pCtx), numOfElems, 1);
272,982✔
4142
  if (numOfElems > 0) {
272,982✔
4143
    pInfo->hasResult = true;
236,816✔
4144
  }
4145

4146
  return TSDB_CODE_SUCCESS;
272,982✔
4147
}
4148

4149
static void spreadTransferInfo(SSpreadInfo* pInput, SSpreadInfo* pOutput) {
22,286✔
4150
  pOutput->hasResult = pInput->hasResult;
22,286✔
4151
  if (pInput->max > pOutput->max) {
22,286✔
4152
    pOutput->max = pInput->max;
17,788✔
4153
  }
4154

4155
  if (pInput->min < pOutput->min) {
22,286✔
4156
    pOutput->min = pInput->min;
17,780✔
4157
  }
4158
}
22,286✔
4159

4160
int32_t spreadFunctionMerge(SqlFunctionCtx* pCtx) {
18,362✔
4161
  SInputColumnInfoData* pInput = &pCtx->input;
18,362✔
4162
  SColumnInfoData*      pCol = pInput->pData[0];
18,362✔
4163

4164
  if (IS_NULL_TYPE(pCol->info.type)) {
18,362!
4165
    SET_VAL(GET_RES_INFO(pCtx), 0, 1);
×
4166
    return TSDB_CODE_SUCCESS;
×
4167
  }
4168

4169
  if (pCol->info.type != TSDB_DATA_TYPE_BINARY) {
18,362!
4170
    return TSDB_CODE_FUNC_FUNTION_PARA_TYPE;
×
4171
  }
4172

4173
  SSpreadInfo* pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
18,362✔
4174

4175
  int32_t start = pInput->startRowIndex;
18,362✔
4176
  for (int32_t i = start; i < start + pInput->numOfRows; ++i) {
40,899✔
4177
    if (colDataIsNull_s(pCol, i)) continue;
45,074!
4178
    char*        data = colDataGetData(pCol, i);
22,537!
4179
    SSpreadInfo* pInputInfo = (SSpreadInfo*)varDataVal(data);
22,537✔
4180
    if (pInputInfo->hasResult) {
22,537✔
4181
      spreadTransferInfo(pInputInfo, pInfo);
22,285✔
4182
    }
4183
  }
4184

4185
  if (pInfo->hasResult) {
18,362✔
4186
    GET_RES_INFO(pCtx)->numOfRes = 1;
18,188✔
4187
  }
4188

4189
  return TSDB_CODE_SUCCESS;
18,362✔
4190
}
4191

4192
int32_t spreadFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
230,222✔
4193
  SSpreadInfo* pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
230,222✔
4194
  if (pInfo->hasResult == true) {
230,222✔
4195
    SET_DOUBLE_VAL(&pInfo->result, pInfo->max - pInfo->min);
194,454✔
4196
  } else {
4197
    GET_RES_INFO(pCtx)->isNullRes = 1;
35,768✔
4198
  }
4199
  return functionFinalize(pCtx, pBlock);
230,222✔
4200
}
4201

4202
int32_t spreadPartialFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
22,317✔
4203
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
22,317✔
4204
  SSpreadInfo*         pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
22,317✔
4205
  int32_t              resultBytes = getSpreadInfoSize();
22,317✔
4206
  char*                res = taosMemoryCalloc(resultBytes + VARSTR_HEADER_SIZE, sizeof(char));
22,317!
4207

4208
  if (NULL == res) {
22,318!
4209
    return terrno;
×
4210
  }
4211
  (void)memcpy(varDataVal(res), pInfo, resultBytes);
22,318✔
4212
  varDataSetLen(res, resultBytes);
22,318✔
4213

4214
  int32_t          slotId = pCtx->pExpr->base.resSchema.slotId;
22,318✔
4215
  int32_t          code = TSDB_CODE_SUCCESS;
22,318✔
4216
  SColumnInfoData* pCol = taosArrayGet(pBlock->pDataBlock, slotId);
22,318✔
4217
  if (NULL == pCol) {
22,317!
4218
    code = terrno;
×
4219
    goto _exit;
×
4220
  }
4221

4222
  code = colDataSetVal(pCol, pBlock->info.rows, res, false);
22,317✔
4223
  if (TSDB_CODE_SUCCESS != code) {
22,316!
4224
    goto _exit;
×
4225
  }
4226

4227
_exit:
22,316✔
4228
  taosMemoryFree(res);
22,316!
4229
  return code;
22,317✔
4230
}
4231

4232
int32_t spreadCombine(SqlFunctionCtx* pDestCtx, SqlFunctionCtx* pSourceCtx) {
1✔
4233
  SResultRowEntryInfo* pDResInfo = GET_RES_INFO(pDestCtx);
1✔
4234
  SSpreadInfo*         pDBuf = GET_ROWCELL_INTERBUF(pDResInfo);
1✔
4235

4236
  SResultRowEntryInfo* pSResInfo = GET_RES_INFO(pSourceCtx);
1✔
4237
  SSpreadInfo*         pSBuf = GET_ROWCELL_INTERBUF(pSResInfo);
1✔
4238
  spreadTransferInfo(pSBuf, pDBuf);
1✔
4239
  pDResInfo->numOfRes = TMAX(pDResInfo->numOfRes, pSResInfo->numOfRes);
1✔
4240
  pDResInfo->isNullRes &= pSResInfo->isNullRes;
1✔
4241
  return TSDB_CODE_SUCCESS;
1✔
4242
}
4243

4244
int32_t getElapsedInfoSize() { return (int32_t)sizeof(SElapsedInfo); }
×
4245

4246
bool getElapsedFuncEnv(SFunctionNode* UNUSED_PARAM(pFunc), SFuncExecEnv* pEnv) {
18,138✔
4247
  pEnv->calcMemSize = sizeof(SElapsedInfo);
18,138✔
4248
  return true;
18,138✔
4249
}
4250

4251
int32_t elapsedFunctionSetup(SqlFunctionCtx* pCtx, SResultRowEntryInfo* pResultInfo) {
35,644✔
4252
  if (pResultInfo->initialized) {
35,644!
4253
    return TSDB_CODE_SUCCESS;
×
4254
  }
4255
  if (TSDB_CODE_SUCCESS != functionSetup(pCtx, pResultInfo)) {
35,644!
4256
    return TSDB_CODE_FUNC_SETUP_ERROR;
×
4257
  }
4258

4259
  SElapsedInfo* pInfo = GET_ROWCELL_INTERBUF(pResultInfo);
35,643✔
4260
  pInfo->result = 0;
35,643✔
4261
  pInfo->min = TSKEY_MAX;
35,643✔
4262
  pInfo->max = 0;
35,643✔
4263

4264
  if (pCtx->numOfParams > 1) {
35,643✔
4265
    pInfo->timeUnit = pCtx->param[1].param.i;
19,369✔
4266
  } else {
4267
    pInfo->timeUnit = 1;
16,274✔
4268
  }
4269

4270
  return TSDB_CODE_SUCCESS;
35,643✔
4271
}
4272

4273
int32_t elapsedFunction(SqlFunctionCtx* pCtx) {
35,692✔
4274
  int32_t numOfElems = 0;
35,692✔
4275

4276
  // Only the pre-computing information loaded and actual data does not loaded
4277
  SInputColumnInfoData* pInput = &pCtx->input;
35,692✔
4278
  SColumnDataAgg*       pAgg = pInput->pColumnDataAgg[0];
35,692✔
4279

4280
  SElapsedInfo* pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
35,692✔
4281

4282
  numOfElems = pInput->numOfRows;  // since this is the primary timestamp, no need to exclude NULL values
35,692✔
4283
  if (numOfElems == 0) {
35,692✔
4284
    // for stream
4285
    if (pCtx->end.key != INT64_MIN) {
52!
4286
      pInfo->max = pCtx->end.key + 1;
52✔
4287
    }
4288
    goto _elapsed_over;
52✔
4289
  }
4290

4291
  if (pInput->colDataSMAIsSet) {
35,640!
4292
    if (pInfo->min == TSKEY_MAX) {
×
4293
      pInfo->min = GET_INT64_VAL(&pAgg->min);
×
4294
      pInfo->max = GET_INT64_VAL(&pAgg->max);
×
4295
    } else {
4296
      if (pCtx->order == TSDB_ORDER_ASC) {
×
4297
        pInfo->max = GET_INT64_VAL(&pAgg->max);
×
4298
      } else {
4299
        pInfo->min = GET_INT64_VAL(&pAgg->min);
×
4300
      }
4301
    }
4302
  } else {  // computing based on the true data block
4303
    if (0 == pInput->numOfRows) {
35,640!
4304
      if (pCtx->order == TSDB_ORDER_DESC) {
×
4305
        if (pCtx->end.key != INT64_MIN) {
×
4306
          pInfo->min = pCtx->end.key;
×
4307
        }
4308
      } else {
4309
        if (pCtx->end.key != INT64_MIN) {
×
4310
          pInfo->max = pCtx->end.key + 1;
×
4311
        }
4312
      }
4313
      goto _elapsed_over;
×
4314
    }
4315

4316
    SColumnInfoData* pCol = pInput->pData[0];
35,640✔
4317

4318
    int32_t start = pInput->startRowIndex;
35,640✔
4319
    TSKEY*  ptsList = (int64_t*)colDataGetData(pCol, 0);
35,640!
4320
    if (pCtx->order == TSDB_ORDER_DESC) {
35,640✔
4321
      if (pCtx->start.key == INT64_MIN) {
162!
4322
        pInfo->max = (pInfo->max < ptsList[start]) ? ptsList[start] : pInfo->max;
162✔
4323
      } else {
4324
        pInfo->max = pCtx->start.key + 1;
×
4325
      }
4326

4327
      if (pCtx->end.key == INT64_MIN) {
162!
4328
        pInfo->min =
162✔
4329
            (pInfo->min > ptsList[start + pInput->numOfRows - 1]) ? ptsList[start + pInput->numOfRows - 1] : pInfo->min;
162✔
4330
      } else {
4331
        pInfo->min = pCtx->end.key;
×
4332
      }
4333
    } else {
4334
      if (pCtx->start.key == INT64_MIN) {
35,478✔
4335
        pInfo->min = (pInfo->min > ptsList[start]) ? ptsList[start] : pInfo->min;
33,549✔
4336
      } else {
4337
        pInfo->min = pCtx->start.key;
1,929✔
4338
      }
4339

4340
      if (pCtx->end.key == INT64_MIN) {
35,478✔
4341
        pInfo->max =
33,327✔
4342
            (pInfo->max < ptsList[start + pInput->numOfRows - 1]) ? ptsList[start + pInput->numOfRows - 1] : pInfo->max;
33,327✔
4343
      } else {
4344
        pInfo->max = pCtx->end.key + 1;
2,151✔
4345
      }
4346
    }
4347
  }
4348

4349
_elapsed_over:
35,692✔
4350
  // data in the check operation are all null, not output
4351
  SET_VAL(GET_RES_INFO(pCtx), numOfElems, 1);
35,692✔
4352

4353
  return TSDB_CODE_SUCCESS;
35,692✔
4354
}
4355

4356
static void elapsedTransferInfo(SElapsedInfo* pInput, SElapsedInfo* pOutput) {
×
4357
  pOutput->timeUnit = pInput->timeUnit;
×
4358
  if (pOutput->min > pInput->min) {
×
4359
    pOutput->min = pInput->min;
×
4360
  }
4361

4362
  if (pOutput->max < pInput->max) {
×
4363
    pOutput->max = pInput->max;
×
4364
  }
4365
}
×
4366

4367
int32_t elapsedFunctionMerge(SqlFunctionCtx* pCtx) {
×
4368
  SInputColumnInfoData* pInput = &pCtx->input;
×
4369
  SColumnInfoData*      pCol = pInput->pData[0];
×
4370
  if (pCol->info.type != TSDB_DATA_TYPE_BINARY) {
×
4371
    return TSDB_CODE_FUNC_FUNTION_PARA_TYPE;
×
4372
  }
4373

4374
  SElapsedInfo* pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
×
4375

4376
  int32_t start = pInput->startRowIndex;
×
4377

4378
  for (int32_t i = start; i < start + pInput->numOfRows; ++i) {
×
4379
    char*         data = colDataGetData(pCol, i);
×
4380
    SElapsedInfo* pInputInfo = (SElapsedInfo*)varDataVal(data);
×
4381
    elapsedTransferInfo(pInputInfo, pInfo);
×
4382
  }
4383

4384
  SET_VAL(GET_RES_INFO(pCtx), 1, 1);
×
4385
  return TSDB_CODE_SUCCESS;
×
4386
}
4387

4388
int32_t elapsedFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
35,715✔
4389
  SElapsedInfo* pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
35,715✔
4390
  double        result = (double)pInfo->max - (double)pInfo->min;
35,715✔
4391
  result = (result >= 0) ? result : -result;
35,715✔
4392
  pInfo->result = result / pInfo->timeUnit;
35,715✔
4393
  return functionFinalize(pCtx, pBlock);
35,715✔
4394
}
4395

4396
int32_t elapsedPartialFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
×
4397
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
×
4398
  SElapsedInfo*        pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
×
4399
  int32_t              resultBytes = getElapsedInfoSize();
×
4400
  char*                res = taosMemoryCalloc(resultBytes + VARSTR_HEADER_SIZE, sizeof(char));
×
4401

4402
  if (NULL == res) {
×
4403
    return terrno;
×
4404
  }
4405
  (void)memcpy(varDataVal(res), pInfo, resultBytes);
×
4406
  varDataSetLen(res, resultBytes);
×
4407

4408
  int32_t          slotId = pCtx->pExpr->base.resSchema.slotId;
×
4409
  int32_t          code = TSDB_CODE_SUCCESS;
×
4410
  SColumnInfoData* pCol = taosArrayGet(pBlock->pDataBlock, slotId);
×
4411
  if (NULL == pCol) {
×
4412
    code = terrno;
×
4413
    goto _exit;
×
4414
  }
4415

4416
  code = colDataSetVal(pCol, pBlock->info.rows, res, false);
×
4417
  if (TSDB_CODE_SUCCESS != code) {
×
4418
    goto _exit;
×
4419
  }
4420
_exit:
×
4421
  taosMemoryFree(res);
×
4422
  return code;
×
4423
}
4424

4425
int32_t elapsedCombine(SqlFunctionCtx* pDestCtx, SqlFunctionCtx* pSourceCtx) {
×
4426
  SResultRowEntryInfo* pDResInfo = GET_RES_INFO(pDestCtx);
×
4427
  SElapsedInfo*        pDBuf = GET_ROWCELL_INTERBUF(pDResInfo);
×
4428

4429
  SResultRowEntryInfo* pSResInfo = GET_RES_INFO(pSourceCtx);
×
4430
  SElapsedInfo*        pSBuf = GET_ROWCELL_INTERBUF(pSResInfo);
×
4431

4432
  elapsedTransferInfo(pSBuf, pDBuf);
×
4433
  pDResInfo->numOfRes = TMAX(pDResInfo->numOfRes, pSResInfo->numOfRes);
×
4434
  pDResInfo->isNullRes &= pSResInfo->isNullRes;
×
4435
  return TSDB_CODE_SUCCESS;
×
4436
}
4437

4438
int32_t getHistogramInfoSize() {
7,591✔
4439
  return (int32_t)sizeof(SHistoFuncInfo) + HISTOGRAM_MAX_BINS_NUM * sizeof(SHistoFuncBin);
7,591✔
4440
}
4441

4442
bool getHistogramFuncEnv(SFunctionNode* UNUSED_PARAM(pFunc), SFuncExecEnv* pEnv) {
10,148✔
4443
  pEnv->calcMemSize = sizeof(SHistoFuncInfo) + HISTOGRAM_MAX_BINS_NUM * sizeof(SHistoFuncBin);
10,148✔
4444
  return true;
10,148✔
4445
}
4446

4447
static int8_t getHistogramBinType(char* binTypeStr) {
7,023✔
4448
  int8_t binType;
4449
  if (strcasecmp(binTypeStr, "user_input") == 0) {
7,023✔
4450
    binType = USER_INPUT_BIN;
2,010✔
4451
  } else if (strcasecmp(binTypeStr, "linear_bin") == 0) {
5,013✔
4452
    binType = LINEAR_BIN;
2,503✔
4453
  } else if (strcasecmp(binTypeStr, "log_bin") == 0) {
2,510!
4454
    binType = LOG_BIN;
2,510✔
4455
  } else {
4456
    binType = UNKNOWN_BIN;
×
4457
  }
4458

4459
  return binType;
7,023✔
4460
}
4461

4462
static int32_t getHistogramBinDesc(SHistoFuncInfo* pInfo, char* binDescStr, int8_t binType, bool normalized) {
7,022✔
4463
  cJSON*  binDesc = cJSON_Parse(binDescStr);
7,022✔
4464
  int32_t numOfBins;
4465
  double* intervals;
4466
  if (cJSON_IsObject(binDesc)) { /* linaer/log bins */
7,023✔
4467
    int32_t numOfParams = cJSON_GetArraySize(binDesc);
5,013✔
4468
    int32_t startIndex;
4469
    if (numOfParams != 4) {
5,013!
4470
      cJSON_Delete(binDesc);
×
4471
      return TSDB_CODE_FAILED;
×
4472
    }
4473

4474
    cJSON* start = cJSON_GetObjectItem(binDesc, "start");
5,013✔
4475
    cJSON* factor = cJSON_GetObjectItem(binDesc, "factor");
5,013✔
4476
    cJSON* width = cJSON_GetObjectItem(binDesc, "width");
5,013✔
4477
    cJSON* count = cJSON_GetObjectItem(binDesc, "count");
5,012✔
4478
    cJSON* infinity = cJSON_GetObjectItem(binDesc, "infinity");
5,012✔
4479

4480
    if (!cJSON_IsNumber(start) || !cJSON_IsNumber(count) || !cJSON_IsBool(infinity)) {
5,012!
4481
      cJSON_Delete(binDesc);
×
4482
      return TSDB_CODE_FAILED;
×
4483
    }
4484

4485
    if (count->valueint <= 0 || count->valueint > 1000) {  // limit count to 1000
5,012!
4486
      cJSON_Delete(binDesc);
×
4487
      return TSDB_CODE_FAILED;
×
4488
    }
4489

4490
    if (isinf(start->valuedouble) || (width != NULL && isinf(width->valuedouble)) ||
5,012!
4491
        (factor != NULL && isinf(factor->valuedouble)) || (count != NULL && isinf(count->valuedouble))) {
5,012!
4492
      cJSON_Delete(binDesc);
×
4493
      return TSDB_CODE_FAILED;
×
4494
    }
4495

4496
    int32_t counter = (int32_t)count->valueint;
5,012✔
4497
    if (infinity->valueint == false) {
5,012✔
4498
      startIndex = 0;
2,971✔
4499
      numOfBins = counter + 1;
2,971✔
4500
    } else {
4501
      startIndex = 1;
2,041✔
4502
      numOfBins = counter + 3;
2,041✔
4503
    }
4504

4505
    intervals = taosMemoryCalloc(numOfBins, sizeof(double));
5,012!
4506
    if (NULL == intervals) {
5,013!
4507
      cJSON_Delete(binDesc);
×
4508
      qError("histogram function out of memory");
×
4509
      return terrno;
×
4510
    }
4511
    if (cJSON_IsNumber(width) && factor == NULL && binType == LINEAR_BIN) {
5,013!
4512
      // linear bin process
4513
      if (width->valuedouble == 0) {
2,503!
4514
        taosMemoryFree(intervals);
×
4515
        cJSON_Delete(binDesc);
×
4516
        return TSDB_CODE_FAILED;
×
4517
      }
4518
      for (int i = 0; i < counter + 1; ++i) {
15,213✔
4519
        intervals[startIndex] = start->valuedouble + i * width->valuedouble;
12,710✔
4520
        if (isinf(intervals[startIndex])) {
12,710!
4521
          taosMemoryFree(intervals);
×
4522
          cJSON_Delete(binDesc);
×
4523
          return TSDB_CODE_FAILED;
×
4524
        }
4525
        startIndex++;
12,710✔
4526
      }
4527
    } else if (cJSON_IsNumber(factor) && width == NULL && binType == LOG_BIN) {
2,510!
4528
      // log bin process
4529
      if (start->valuedouble == 0) {
2,510!
4530
        taosMemoryFree(intervals);
×
4531
        cJSON_Delete(binDesc);
×
4532
        return TSDB_CODE_FAILED;
×
4533
      }
4534
      if (factor->valuedouble < 0 || factor->valuedouble == 0 || factor->valuedouble == 1) {
2,510!
4535
        taosMemoryFree(intervals);
×
4536
        cJSON_Delete(binDesc);
×
4537
        return TSDB_CODE_FAILED;
×
4538
      }
4539
      for (int i = 0; i < counter + 1; ++i) {
15,263✔
4540
        intervals[startIndex] = start->valuedouble * pow(factor->valuedouble, i * 1.0);
12,753✔
4541
        if (isinf(intervals[startIndex])) {
12,753!
4542
          taosMemoryFree(intervals);
×
4543
          cJSON_Delete(binDesc);
×
4544
          return TSDB_CODE_FAILED;
×
4545
        }
4546
        startIndex++;
12,753✔
4547
      }
4548
    } else {
4549
      taosMemoryFree(intervals);
×
4550
      cJSON_Delete(binDesc);
×
4551
      return TSDB_CODE_FAILED;
×
4552
    }
4553

4554
    if (infinity->valueint == true) {
5,013✔
4555
      intervals[0] = -INFINITY;
2,041✔
4556
      intervals[numOfBins - 1] = INFINITY;
2,041✔
4557
      // in case of desc bin orders, -inf/inf should be swapped
4558
      if (numOfBins < 4) {
2,041!
4559
        return TSDB_CODE_FAILED;
×
4560
      }
4561
      if (intervals[1] > intervals[numOfBins - 2]) {
2,041✔
4562
        TSWAP(intervals[0], intervals[numOfBins - 1]);
1,933✔
4563
      }
4564
    }
4565
  } else if (cJSON_IsArray(binDesc)) { /* user input bins */
2,008!
4566
    if (binType != USER_INPUT_BIN) {
2,009!
4567
      cJSON_Delete(binDesc);
×
4568
      return TSDB_CODE_FAILED;
×
4569
    }
4570
    numOfBins = cJSON_GetArraySize(binDesc);
2,009✔
4571
    intervals = taosMemoryCalloc(numOfBins, sizeof(double));
2,010!
4572
    if (NULL == intervals) {
2,010!
4573
      cJSON_Delete(binDesc);
×
4574
      qError("histogram function out of memory");
×
4575
      return terrno;
×
4576
    }
4577
    cJSON* bin = binDesc->child;
2,010✔
4578
    if (bin == NULL) {
2,010!
4579
      taosMemoryFree(intervals);
×
4580
      cJSON_Delete(binDesc);
×
4581
      return TSDB_CODE_FAILED;
×
4582
    }
4583
    int i = 0;
2,010✔
4584
    while (bin) {
7,745✔
4585
      intervals[i] = bin->valuedouble;
5,734✔
4586
      if (!cJSON_IsNumber(bin)) {
5,734!
4587
        taosMemoryFree(intervals);
×
4588
        cJSON_Delete(binDesc);
×
4589
        return TSDB_CODE_FAILED;
×
4590
      }
4591
      if (i != 0 && intervals[i] <= intervals[i - 1]) {
5,735!
4592
        taosMemoryFree(intervals);
×
4593
        cJSON_Delete(binDesc);
×
4594
        return TSDB_CODE_FAILED;
×
4595
      }
4596
      bin = bin->next;
5,735✔
4597
      i++;
5,735✔
4598
    }
4599
  } else {
4600
    cJSON_Delete(binDesc);
×
4601
    return TSDB_CODE_FAILED;
×
4602
  }
4603

4604
  pInfo->numOfBins = numOfBins - 1;
7,024✔
4605
  pInfo->normalized = normalized;
7,024✔
4606
  for (int32_t i = 0; i < pInfo->numOfBins; ++i) {
35,279✔
4607
    pInfo->bins[i].lower = intervals[i] < intervals[i + 1] ? intervals[i] : intervals[i + 1];
28,255✔
4608
    pInfo->bins[i].upper = intervals[i + 1] > intervals[i] ? intervals[i + 1] : intervals[i];
28,255✔
4609
    pInfo->bins[i].count = 0;
28,255✔
4610
  }
4611

4612
  taosMemoryFree(intervals);
7,024✔
4613
  cJSON_Delete(binDesc);
7,022✔
4614

4615
  return TSDB_CODE_SUCCESS;
7,022✔
4616
}
4617

4618
int32_t histogramFunctionSetup(SqlFunctionCtx* pCtx, SResultRowEntryInfo* pResultInfo) {
7,022✔
4619
  if (pResultInfo->initialized) {
7,022!
4620
    return TSDB_CODE_SUCCESS;
×
4621
  }
4622
  if (TSDB_CODE_SUCCESS != functionSetup(pCtx, pResultInfo)) {
7,022!
4623
    return TSDB_CODE_FUNC_SETUP_ERROR;
×
4624
  }
4625

4626
  SHistoFuncInfo* pInfo = GET_ROWCELL_INTERBUF(pResultInfo);
7,023✔
4627
  pInfo->numOfBins = 0;
7,023✔
4628
  pInfo->totalCount = 0;
7,023✔
4629
  pInfo->normalized = 0;
7,023✔
4630

4631
  char* binTypeStr = taosStrndup(varDataVal(pCtx->param[1].param.pz), varDataLen(pCtx->param[1].param.pz));
7,023!
4632
  if (binTypeStr == NULL) {
7,023!
4633
    return terrno;
×
4634
  }
4635
  int8_t binType = getHistogramBinType(binTypeStr);
7,023✔
4636
  taosMemoryFree(binTypeStr);
7,023!
4637

4638
  if (binType == UNKNOWN_BIN) {
7,023!
4639
    return TSDB_CODE_FUNC_FUNTION_PARA_VALUE;
×
4640
  }
4641
  char* binDesc = taosStrndup(varDataVal(pCtx->param[2].param.pz), varDataLen(pCtx->param[2].param.pz));
7,023!
4642
  if (binDesc == NULL) {
7,022!
4643
    return terrno;
×
4644
  }
4645
  int64_t normalized = pCtx->param[3].param.i;
7,022✔
4646
  if (normalized != 0 && normalized != 1) {
7,022!
4647
    taosMemoryFree(binDesc);
×
4648
    return TSDB_CODE_FUNC_FUNTION_PARA_VALUE;
×
4649
  }
4650
  int32_t code = getHistogramBinDesc(pInfo, binDesc, binType, (bool)normalized);
7,022✔
4651
  if (TSDB_CODE_SUCCESS != code) {
7,022!
4652
    taosMemoryFree(binDesc);
×
4653
    return code;
×
4654
  }
4655
  taosMemoryFree(binDesc);
7,022!
4656

4657
  return TSDB_CODE_SUCCESS;
7,022✔
4658
}
4659

4660
static int32_t histogramFunctionImpl(SqlFunctionCtx* pCtx, bool isPartial) {
7,929✔
4661
  SHistoFuncInfo* pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
7,929✔
4662

4663
  SInputColumnInfoData* pInput = &pCtx->input;
7,929✔
4664
  SColumnInfoData*      pCol = pInput->pData[0];
7,929✔
4665

4666
  int32_t type = pInput->pData[0]->info.type;
7,929✔
4667

4668
  int32_t start = pInput->startRowIndex;
7,929✔
4669
  int32_t numOfRows = pInput->numOfRows;
7,929✔
4670

4671
  int32_t numOfElems = 0;
7,929✔
4672
  for (int32_t i = start; i < numOfRows + start; ++i) {
1,205,631✔
4673
    if (pCol->hasNull && colDataIsNull_f(pCol->nullbitmap, i)) {
1,197,702✔
4674
      continue;
603,340✔
4675
    }
4676

4677
    numOfElems++;
594,362✔
4678

4679
    char*  data = colDataGetData(pCol, i);
594,362!
4680
    double v;
4681
    GET_TYPED_DATA(v, double, type, data);
594,362!
4682

4683
    for (int32_t k = 0; k < pInfo->numOfBins; ++k) {
1,665,983✔
4684
      if (v > pInfo->bins[k].lower && v <= pInfo->bins[k].upper) {
1,352,483✔
4685
        pInfo->bins[k].count++;
280,862✔
4686
        pInfo->totalCount++;
280,862✔
4687
        break;
280,862✔
4688
      }
4689
    }
4690
  }
4691

4692
  if (!isPartial) {
7,929✔
4693
    GET_RES_INFO(pCtx)->numOfRes = pInfo->numOfBins;
5,449✔
4694
  } else {
4695
    GET_RES_INFO(pCtx)->numOfRes = 1;
2,480✔
4696
  }
4697
  return TSDB_CODE_SUCCESS;
7,929✔
4698
}
4699

4700
int32_t histogramFunction(SqlFunctionCtx* pCtx) { return histogramFunctionImpl(pCtx, false); }
5,448✔
4701

4702
int32_t histogramFunctionPartial(SqlFunctionCtx* pCtx) { return histogramFunctionImpl(pCtx, true); }
2,480✔
4703

4704
static void histogramTransferInfo(SHistoFuncInfo* pInput, SHistoFuncInfo* pOutput) {
1,580✔
4705
  pOutput->normalized = pInput->normalized;
1,580✔
4706
  pOutput->numOfBins = pInput->numOfBins;
1,580✔
4707
  pOutput->totalCount += pInput->totalCount;
1,580✔
4708
  for (int32_t k = 0; k < pOutput->numOfBins; ++k) {
10,364✔
4709
    pOutput->bins[k].lower = pInput->bins[k].lower;
8,784✔
4710
    pOutput->bins[k].upper = pInput->bins[k].upper;
8,784✔
4711
    pOutput->bins[k].count += pInput->bins[k].count;
8,784✔
4712
  }
4713
}
1,580✔
4714

4715
int32_t histogramFunctionMerge(SqlFunctionCtx* pCtx) {
1,579✔
4716
  SInputColumnInfoData* pInput = &pCtx->input;
1,579✔
4717
  SColumnInfoData*      pCol = pInput->pData[0];
1,579✔
4718
  if (pCol->info.type != TSDB_DATA_TYPE_BINARY) {
1,579!
4719
    return TSDB_CODE_FUNC_FUNTION_PARA_TYPE;
×
4720
  }
4721

4722
  SHistoFuncInfo* pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
1,579✔
4723

4724
  int32_t start = pInput->startRowIndex;
1,579✔
4725

4726
  for (int32_t i = start; i < start + pInput->numOfRows; ++i) {
3,159✔
4727
    char*           data = colDataGetData(pCol, i);
1,580!
4728
    SHistoFuncInfo* pInputInfo = (SHistoFuncInfo*)varDataVal(data);
1,580✔
4729
    histogramTransferInfo(pInputInfo, pInfo);
1,580✔
4730
  }
4731

4732
  SET_VAL(GET_RES_INFO(pCtx), pInfo->numOfBins, pInfo->numOfBins);
1,579!
4733
  return TSDB_CODE_SUCCESS;
1,579✔
4734
}
4735

4736
int32_t histogramFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
6,925✔
4737
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
6,925✔
4738
  SHistoFuncInfo*      pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
6,925✔
4739
  int32_t              slotId = pCtx->pExpr->base.resSchema.slotId;
6,925✔
4740
  SColumnInfoData*     pCol = taosArrayGet(pBlock->pDataBlock, slotId);
6,925✔
4741
  int32_t              code = TSDB_CODE_SUCCESS;
6,925✔
4742

4743
  int32_t currentRow = pBlock->info.rows;
6,925✔
4744
  if (NULL == pCol) {
6,925!
4745
    return TSDB_CODE_OUT_OF_RANGE;
×
4746
  }
4747

4748
  if (pInfo->normalized) {
6,925✔
4749
    for (int32_t k = 0; k < pResInfo->numOfRes; ++k) {
14,406✔
4750
      if (pInfo->totalCount != 0) {
10,881✔
4751
        pInfo->bins[k].percentage = pInfo->bins[k].count / (double)pInfo->totalCount;
4,886✔
4752
      } else {
4753
        pInfo->bins[k].percentage = 0;
5,995✔
4754
      }
4755
    }
4756
  }
4757

4758
  for (int32_t i = 0; i < pResInfo->numOfRes; ++i) {
34,566✔
4759
    int32_t len;
4760
    char    buf[512] = {0};
27,646✔
4761
    if (!pInfo->normalized) {
27,646✔
4762
      len = tsnprintf(varDataVal(buf), sizeof(buf) - VARSTR_HEADER_SIZE,
16,764✔
4763
                      "{\"lower_bin\":%g, \"upper_bin\":%g, \"count\":%" PRId64 "}", pInfo->bins[i].lower,
4764
                      pInfo->bins[i].upper, pInfo->bins[i].count);
4765
    } else {
4766
      len = tsnprintf(varDataVal(buf), sizeof(buf) - VARSTR_HEADER_SIZE,
10,882✔
4767
                      "{\"lower_bin\":%g, \"upper_bin\":%g, \"count\":%lf}", pInfo->bins[i].lower, pInfo->bins[i].upper,
4768
                      pInfo->bins[i].percentage);
4769
    }
4770
    varDataSetLen(buf, len);
27,647✔
4771
    code = colDataSetVal(pCol, currentRow, buf, false);
27,647✔
4772
    if (TSDB_CODE_SUCCESS != code) {
27,641!
4773
      return code;
×
4774
    }
4775
    currentRow++;
27,641✔
4776
  }
4777

4778
  return code;
6,920✔
4779
}
4780

4781
int32_t histogramPartialFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
1,580✔
4782
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
1,580✔
4783
  SHistoFuncInfo*      pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
1,580✔
4784
  int32_t              resultBytes = getHistogramInfoSize();
1,580✔
4785
  char*                res = taosMemoryCalloc(resultBytes + VARSTR_HEADER_SIZE, sizeof(char));
1,580!
4786

4787
  if (NULL == res) {
1,580!
4788
    return terrno;
×
4789
  }
4790
  (void)memcpy(varDataVal(res), pInfo, resultBytes);
1,580✔
4791
  varDataSetLen(res, resultBytes);
1,580✔
4792

4793
  int32_t          slotId = pCtx->pExpr->base.resSchema.slotId;
1,580✔
4794
  int32_t          code = TSDB_CODE_SUCCESS;
1,580✔
4795
  SColumnInfoData* pCol = taosArrayGet(pBlock->pDataBlock, slotId);
1,580✔
4796
  if (NULL == pCol) {
1,580!
4797
    code = terrno;
×
4798
    goto _exit;
×
4799
  }
4800
  code = colDataSetVal(pCol, pBlock->info.rows, res, false);
1,580✔
4801

4802
_exit:
1,580✔
4803
  taosMemoryFree(res);
1,580!
4804
  return code;
1,580✔
4805
}
4806

4807
int32_t histogramCombine(SqlFunctionCtx* pDestCtx, SqlFunctionCtx* pSourceCtx) {
×
4808
  SResultRowEntryInfo* pDResInfo = GET_RES_INFO(pDestCtx);
×
4809
  SHistoFuncInfo*      pDBuf = GET_ROWCELL_INTERBUF(pDResInfo);
×
4810

4811
  SResultRowEntryInfo* pSResInfo = GET_RES_INFO(pSourceCtx);
×
4812
  SHistoFuncInfo*      pSBuf = GET_ROWCELL_INTERBUF(pSResInfo);
×
4813

4814
  histogramTransferInfo(pSBuf, pDBuf);
×
4815
  pDResInfo->numOfRes = TMAX(pDResInfo->numOfRes, pSResInfo->numOfRes);
×
4816
  pDResInfo->isNullRes &= pSResInfo->isNullRes;
×
4817
  return TSDB_CODE_SUCCESS;
×
4818
}
4819

4820
int32_t getHLLInfoSize() { return (int32_t)sizeof(SHLLInfo); }
11,419✔
4821

4822
bool getHLLFuncEnv(SFunctionNode* UNUSED_PARAM(pFunc), SFuncExecEnv* pEnv) {
62,901✔
4823
  pEnv->calcMemSize = sizeof(SHLLInfo);
62,901✔
4824
  return true;
62,901✔
4825
}
4826

4827
static uint8_t hllCountNum(void* data, int32_t bytes, int32_t* buk) {
3,473,192✔
4828
  uint64_t hash = MurmurHash3_64(data, bytes);
3,473,192✔
4829
  int32_t  index = hash & HLL_BUCKET_MASK;
3,472,544✔
4830
  hash >>= HLL_BUCKET_BITS;
3,472,544✔
4831
  hash |= ((uint64_t)1 << HLL_DATA_BITS);
3,472,544✔
4832
  uint64_t bit = 1;
3,472,544✔
4833
  uint8_t  count = 1;
3,472,544✔
4834
  while ((hash & bit) == 0) {
6,381,556✔
4835
    count++;
2,909,012✔
4836
    bit <<= 1;
2,909,012✔
4837
  }
4838
  *buk = index;
3,472,544✔
4839
  return count;
3,472,544✔
4840
}
4841

4842
static void hllBucketHisto(uint8_t* buckets, int32_t* bucketHisto) {
223,664✔
4843
  uint64_t* word = (uint64_t*)buckets;
223,664✔
4844
  uint8_t*  bytes;
4845

4846
  for (int32_t j = 0; j < HLL_BUCKETS >> 3; j++) {
451,084,419✔
4847
    if (*word == 0) {
450,860,755✔
4848
      bucketHisto[0] += 8;
449,967,655✔
4849
    } else {
4850
      bytes = (uint8_t*)word;
893,100✔
4851
      bucketHisto[bytes[0]]++;
893,100✔
4852
      bucketHisto[bytes[1]]++;
893,100✔
4853
      bucketHisto[bytes[2]]++;
893,100✔
4854
      bucketHisto[bytes[3]]++;
893,100✔
4855
      bucketHisto[bytes[4]]++;
893,100✔
4856
      bucketHisto[bytes[5]]++;
893,100✔
4857
      bucketHisto[bytes[6]]++;
893,100✔
4858
      bucketHisto[bytes[7]]++;
893,100✔
4859
    }
4860
    word++;
450,860,755✔
4861
  }
4862
}
223,664✔
4863
static double hllTau(double x) {
223,668✔
4864
  if (x == 0. || x == 1.) return 0.;
223,668!
4865
  double zPrime;
4866
  double y = 1.0;
×
4867
  double z = 1 - x;
×
4868
  do {
4869
    x = sqrt(x);
×
4870
    zPrime = z;
×
4871
    y *= 0.5;
×
4872
    z -= pow(1 - x, 2) * y;
×
4873
  } while (zPrime != z);
×
4874
  return z / 3;
×
4875
}
4876

4877
static double hllSigma(double x) {
223,680✔
4878
  if (x == 1.0) return INFINITY;
223,680✔
4879
  double zPrime;
4880
  double y = 1;
189,774✔
4881
  double z = x;
189,774✔
4882
  do {
4883
    x *= x;
3,716,035✔
4884
    zPrime = z;
3,716,035✔
4885
    z += x * y;
3,716,035✔
4886
    y += y;
3,716,035✔
4887
  } while (zPrime != z);
3,716,035✔
4888
  return z;
189,774✔
4889
}
4890

4891
// estimate the cardinality, the algorithm refer this paper: "New cardinality estimation algorithms for HyperLogLog
4892
// sketches"
4893
static uint64_t hllCountCnt(uint8_t* buckets) {
223,637✔
4894
  double  m = HLL_BUCKETS;
223,637✔
4895
  int32_t buckethisto[64] = {0};
223,637✔
4896
  hllBucketHisto(buckets, buckethisto);
223,637✔
4897

4898
  double z = m * hllTau((m - buckethisto[HLL_DATA_BITS + 1]) / (double)m);
223,668✔
4899
  for (int j = HLL_DATA_BITS; j >= 1; --j) {
11,403,876✔
4900
    z += buckethisto[j];
11,180,196✔
4901
    z *= 0.5;
11,180,196✔
4902
  }
4903

4904
  z += m * hllSigma(buckethisto[0] / (double)m);
223,680✔
4905
  double E = (double)llroundl(HLL_ALPHA_INF * m * m / z);
223,680✔
4906

4907
  return (uint64_t)E;
223,680✔
4908
}
4909

4910
int32_t hllFunction(SqlFunctionCtx* pCtx) {
246,628✔
4911
  SHLLInfo* pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
246,628✔
4912

4913
  SInputColumnInfoData* pInput = &pCtx->input;
246,628✔
4914
  SColumnInfoData*      pCol = pInput->pData[0];
246,628✔
4915

4916
  int32_t type = pCol->info.type;
246,628✔
4917
  int32_t bytes = pCol->info.bytes;
246,628✔
4918

4919
  int32_t start = pInput->startRowIndex;
246,628✔
4920
  int32_t numOfRows = pInput->numOfRows;
246,628✔
4921

4922
  int32_t numOfElems = 0;
246,628✔
4923
  if (IS_NULL_TYPE(type)) {
246,628✔
4924
    goto _hll_over;
1,545✔
4925
  }
4926

4927
  for (int32_t i = start; i < numOfRows + start; ++i) {
4,761,923✔
4928
    if (pCol->hasNull && colDataIsNull_s(pCol, i)) {
6,187,939!
4929
      continue;
1,043,317✔
4930
    }
4931

4932
    numOfElems++;
3,474,204✔
4933

4934
    char* data = colDataGetData(pCol, i);
3,474,204!
4935
    if (IS_VAR_DATA_TYPE(type)) {
3,474,204!
4936
      bytes = varDataLen(data);
1,036,250✔
4937
      data = varDataVal(data);
1,036,250✔
4938
    }
4939

4940
    int32_t index = 0;
3,474,204✔
4941
    uint8_t count = hllCountNum(data, bytes, &index);
3,474,204✔
4942
    uint8_t oldcount = pInfo->buckets[index];
3,473,523✔
4943
    if (count > oldcount) {
3,473,523✔
4944
      pInfo->buckets[index] = count;
921,901✔
4945
    }
4946
  }
4947

4948
_hll_over:
244,402✔
4949
  pInfo->totalCount += numOfElems;
245,947✔
4950

4951
  if (pInfo->totalCount == 0 && !tsCountAlwaysReturnValue) {
245,947✔
4952
    SET_VAL(GET_RES_INFO(pCtx), 0, 1);
1,851✔
4953
  } else {
4954
    SET_VAL(GET_RES_INFO(pCtx), 1, 1);
244,096✔
4955
  }
4956

4957
  return TSDB_CODE_SUCCESS;
245,947✔
4958
}
4959

4960
static void hllTransferInfo(SHLLInfo* pInput, SHLLInfo* pOutput) {
11,707✔
4961
  for (int32_t k = 0; k < HLL_BUCKETS; ++k) {
187,738,515✔
4962
    if (pOutput->buckets[k] < pInput->buckets[k]) {
187,726,808✔
4963
      pOutput->buckets[k] = pInput->buckets[k];
130,485✔
4964
    }
4965
  }
4966
  pOutput->totalCount += pInput->totalCount;
11,707✔
4967
}
11,707✔
4968

4969
int32_t hllFunctionMerge(SqlFunctionCtx* pCtx) {
11,656✔
4970
  SInputColumnInfoData* pInput = &pCtx->input;
11,656✔
4971
  SColumnInfoData*      pCol = pInput->pData[0];
11,656✔
4972

4973
  if (IS_NULL_TYPE(pCol->info.type)) {
11,656!
4974
    SET_VAL(GET_RES_INFO(pCtx), 0, 1);
×
4975
    return TSDB_CODE_SUCCESS;
×
4976
  }
4977

4978
  if (pCol->info.type != TSDB_DATA_TYPE_BINARY) {
11,656!
4979
    return TSDB_CODE_SUCCESS;
×
4980
  }
4981

4982
  SHLLInfo* pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
11,656✔
4983

4984
  int32_t start = pInput->startRowIndex;
11,656✔
4985

4986
  for (int32_t i = start; i < start + pInput->numOfRows; ++i) {
23,361✔
4987
    if (colDataIsNull_s(pCol, i)) continue;
23,412!
4988
    char*     data = colDataGetData(pCol, i);
11,706!
4989
    SHLLInfo* pInputInfo = (SHLLInfo*)varDataVal(data);
11,706✔
4990
    hllTransferInfo(pInputInfo, pInfo);
11,706✔
4991
  }
4992

4993
  if (pInfo->totalCount == 0 && !tsCountAlwaysReturnValue) {
11,655✔
4994
    SET_VAL(GET_RES_INFO(pCtx), 0, 1);
3✔
4995
  } else {
4996
    SET_VAL(GET_RES_INFO(pCtx), 1, 1);
11,652✔
4997
  }
4998

4999
  return TSDB_CODE_SUCCESS;
11,655✔
5000
}
5001

5002
int32_t hllFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
223,637✔
5003
  SResultRowEntryInfo* pInfo = GET_RES_INFO(pCtx);
223,637✔
5004

5005
  SHLLInfo* pHllInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
223,637✔
5006
  pHllInfo->result = hllCountCnt(pHllInfo->buckets);
223,637✔
5007
  if (tsCountAlwaysReturnValue && pHllInfo->result == 0) {
223,686✔
5008
    pInfo->numOfRes = 1;
32,079✔
5009
  }
5010

5011
  return functionFinalize(pCtx, pBlock);
223,686✔
5012
}
5013

5014
int32_t hllPartialFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
11,419✔
5015
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
11,419✔
5016
  SHLLInfo*            pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
11,419✔
5017
  int32_t              resultBytes = getHLLInfoSize();
11,419✔
5018
  char*                res = taosMemoryCalloc(resultBytes + VARSTR_HEADER_SIZE, sizeof(char));
11,418!
5019

5020
  if (NULL == res) {
11,419!
5021
    return terrno;
×
5022
  }
5023
  (void)memcpy(varDataVal(res), pInfo, resultBytes);
11,419✔
5024
  varDataSetLen(res, resultBytes);
11,419✔
5025

5026
  int32_t          slotId = pCtx->pExpr->base.resSchema.slotId;
11,419✔
5027
  int32_t          code = TSDB_CODE_SUCCESS;
11,419✔
5028
  SColumnInfoData* pCol = taosArrayGet(pBlock->pDataBlock, slotId);
11,419✔
5029
  if (NULL == pCol) {
11,419!
5030
    code = terrno;
×
5031
    goto _exit;
×
5032
  }
5033

5034
  code = colDataSetVal(pCol, pBlock->info.rows, res, false);
11,419✔
5035

5036
_exit:
11,419✔
5037
  taosMemoryFree(res);
11,419!
5038
  return code;
11,419✔
5039
}
5040

5041
int32_t hllCombine(SqlFunctionCtx* pDestCtx, SqlFunctionCtx* pSourceCtx) {
1✔
5042
  SResultRowEntryInfo* pDResInfo = GET_RES_INFO(pDestCtx);
1✔
5043
  SHLLInfo*            pDBuf = GET_ROWCELL_INTERBUF(pDResInfo);
1✔
5044

5045
  SResultRowEntryInfo* pSResInfo = GET_RES_INFO(pSourceCtx);
1✔
5046
  SHLLInfo*            pSBuf = GET_ROWCELL_INTERBUF(pSResInfo);
1✔
5047

5048
  hllTransferInfo(pSBuf, pDBuf);
1✔
5049
  pDResInfo->numOfRes = TMAX(pDResInfo->numOfRes, pSResInfo->numOfRes);
1✔
5050
  pDResInfo->isNullRes &= pSResInfo->isNullRes;
1✔
5051
  return TSDB_CODE_SUCCESS;
1✔
5052
}
5053

5054
bool getStateFuncEnv(SFunctionNode* UNUSED_PARAM(pFunc), SFuncExecEnv* pEnv) {
7,658✔
5055
  pEnv->calcMemSize = sizeof(SStateInfo);
7,658✔
5056
  return true;
7,658✔
5057
}
5058

5059
static int8_t getStateOpType(char* opStr) {
7,874✔
5060
  int8_t opType;
5061
  if (strncasecmp(opStr, "LT", 2) == 0) {
7,874✔
5062
    opType = STATE_OPER_LT;
1,351✔
5063
  } else if (strncasecmp(opStr, "GT", 2) == 0) {
6,523✔
5064
    opType = STATE_OPER_GT;
3,420✔
5065
  } else if (strncasecmp(opStr, "LE", 2) == 0) {
3,103✔
5066
    opType = STATE_OPER_LE;
496✔
5067
  } else if (strncasecmp(opStr, "GE", 2) == 0) {
2,607✔
5068
    opType = STATE_OPER_GE;
588✔
5069
  } else if (strncasecmp(opStr, "NE", 2) == 0) {
2,019✔
5070
    opType = STATE_OPER_NE;
1,523✔
5071
  } else if (strncasecmp(opStr, "EQ", 2) == 0) {
496!
5072
    opType = STATE_OPER_EQ;
496✔
5073
  } else {
5074
    opType = STATE_OPER_INVALID;
×
5075
  }
5076

5077
  return opType;
7,874✔
5078
}
5079

5080
static bool checkStateOp(int8_t op, SColumnInfoData* pCol, int32_t index, SVariant param) {
427,010✔
5081
  char* data = colDataGetData(pCol, index);
427,010!
5082
  switch (pCol->info.type) {
427,010!
5083
    case TSDB_DATA_TYPE_TINYINT: {
84,048✔
5084
      int8_t v = *(int8_t*)data;
84,048✔
5085
      STATE_COMP(op, v, param);
84,048!
5086
      break;
×
5087
    }
5088
    case TSDB_DATA_TYPE_UTINYINT: {
2,880✔
5089
      uint8_t v = *(uint8_t*)data;
2,880✔
5090
      STATE_COMP(op, v, param);
2,880!
5091
      break;
×
5092
    }
5093
    case TSDB_DATA_TYPE_SMALLINT: {
22,356✔
5094
      int16_t v = *(int16_t*)data;
22,356✔
5095
      STATE_COMP(op, v, param);
22,356!
5096
      break;
×
5097
    }
5098
    case TSDB_DATA_TYPE_USMALLINT: {
2,880✔
5099
      uint16_t v = *(uint16_t*)data;
2,880✔
5100
      STATE_COMP(op, v, param);
2,880!
5101
      break;
×
5102
    }
5103
    case TSDB_DATA_TYPE_INT: {
40,768✔
5104
      int32_t v = *(int32_t*)data;
40,768✔
5105
      STATE_COMP(op, v, param);
40,768!
5106
      break;
×
5107
    }
5108
    case TSDB_DATA_TYPE_UINT: {
2,880✔
5109
      uint32_t v = *(uint32_t*)data;
2,880✔
5110
      STATE_COMP(op, v, param);
2,880!
5111
      break;
×
5112
    }
5113
    case TSDB_DATA_TYPE_BIGINT: {
110,384✔
5114
      int64_t v = *(int64_t*)data;
110,384✔
5115
      STATE_COMP(op, v, param);
110,384!
5116
      break;
×
5117
    }
5118
    case TSDB_DATA_TYPE_UBIGINT: {
2,880✔
5119
      uint64_t v = *(uint64_t*)data;
2,880✔
5120
      STATE_COMP(op, v, param);
2,880!
5121
      break;
×
5122
    }
5123
    case TSDB_DATA_TYPE_FLOAT: {
3,056✔
5124
      float v = *(float*)data;
3,056✔
5125
      STATE_COMP(op, v, param);
3,056!
5126
      break;
×
5127
    }
5128
    case TSDB_DATA_TYPE_DOUBLE: {
154,878✔
5129
      double v = *(double*)data;
154,878✔
5130
      STATE_COMP(op, v, param);
154,878!
UNCOV
5131
      break;
×
5132
    }
5133
    default: {
×
5134
      return false;
×
5135
    }
5136
  }
UNCOV
5137
  return false;
×
5138
}
5139

5140
int32_t stateCountFunction(SqlFunctionCtx* pCtx) {
2,664✔
5141
  int32_t              code = TSDB_CODE_SUCCESS;
2,664✔
5142
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
2,664✔
5143
  SStateInfo*          pInfo = GET_ROWCELL_INTERBUF(pResInfo);
2,664✔
5144

5145
  SInputColumnInfoData* pInput = &pCtx->input;
2,664✔
5146
  TSKEY*                tsList = (int64_t*)pInput->pPTS->pData;
2,664✔
5147

5148
  SColumnInfoData* pInputCol = pInput->pData[0];
2,664✔
5149

5150
  int32_t          numOfElems = 0;
2,664✔
5151
  SColumnInfoData* pOutput = (SColumnInfoData*)pCtx->pOutput;
2,664✔
5152

5153
  int8_t op = getStateOpType(varDataVal(pCtx->param[1].param.pz));
2,664✔
5154
  if (STATE_OPER_INVALID == op) {
2,664!
5155
    return 0;
×
5156
  }
5157

5158
  for (int32_t i = pInput->startRowIndex; i < pInput->numOfRows + pInput->startRowIndex; i += 1) {
481,514✔
5159
    if (pInfo->isPrevTsSet == true && tsList[i] == pInfo->prevTs) {
478,850!
5160
      return TSDB_CODE_FUNC_DUP_TIMESTAMP;
×
5161
    } else {
5162
      pInfo->prevTs = tsList[i];
478,850✔
5163
    }
5164

5165
    pInfo->isPrevTsSet = true;
478,850✔
5166
    numOfElems++;
478,850✔
5167

5168
    if (colDataIsNull_f(pInputCol->nullbitmap, i)) {
478,850✔
5169
      colDataSetNULL(pOutput, i);
219,441!
5170
      // handle selectivity
5171
      if (pCtx->subsidiaries.num > 0) {
219,441✔
5172
        code = appendSelectivityValue(pCtx, i, pCtx->offset + numOfElems - 1);
22✔
5173
        if (TSDB_CODE_SUCCESS != code) {
22!
5174
          return code;
×
5175
        }
5176
      }
5177
      continue;
219,441✔
5178
    }
5179

5180
    bool ret = checkStateOp(op, pInputCol, i, pCtx->param[2].param);
259,409✔
5181

5182
    int64_t output = -1;
259,409✔
5183
    if (ret) {
259,409✔
5184
      output = ++pInfo->count;
173,189✔
5185
    } else {
5186
      pInfo->count = 0;
86,220✔
5187
    }
5188
    code = colDataSetVal(pOutput, pCtx->offset + numOfElems - 1, (char*)&output, false);
259,409✔
5189
    if (TSDB_CODE_SUCCESS != code) {
259,409!
5190
      return code;
×
5191
    }
5192

5193
    // handle selectivity
5194
    if (pCtx->subsidiaries.num > 0) {
259,409✔
5195
      code = appendSelectivityValue(pCtx, i, pCtx->offset + numOfElems - 1);
264✔
5196
      if (TSDB_CODE_SUCCESS != code) {
264!
5197
        return code;
×
5198
      }
5199
    }
5200
  }
5201

5202
  pResInfo->numOfRes = numOfElems;
2,664✔
5203
  return TSDB_CODE_SUCCESS;
2,664✔
5204
}
5205

5206
int32_t stateDurationFunction(SqlFunctionCtx* pCtx) {
5,210✔
5207
  int32_t              code = TSDB_CODE_SUCCESS;
5,210✔
5208
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
5,210✔
5209
  SStateInfo*          pInfo = GET_ROWCELL_INTERBUF(pResInfo);
5,210✔
5210

5211
  SInputColumnInfoData* pInput = &pCtx->input;
5,210✔
5212
  TSKEY*                tsList = (int64_t*)pInput->pPTS->pData;
5,210✔
5213

5214
  SColumnInfoData* pInputCol = pInput->pData[0];
5,210✔
5215

5216
  int32_t          numOfElems = 0;
5,210✔
5217
  SColumnInfoData* pOutput = (SColumnInfoData*)pCtx->pOutput;
5,210✔
5218

5219
  // TODO: process timeUnit for different db precisions
5220
  int32_t timeUnit = 1;
5,210✔
5221
  if (pCtx->numOfParams == 5) {  // TODO: param number incorrect
5,210✔
5222
    timeUnit = pCtx->param[3].param.i;
4,229✔
5223
  }
5224

5225
  int8_t op = getStateOpType(varDataVal(pCtx->param[1].param.pz));
5,210✔
5226
  if (STATE_OPER_INVALID == op) {
5,210!
5227
    return TSDB_CODE_INVALID_PARA;
×
5228
  }
5229

5230
  for (int32_t i = pInput->startRowIndex; i < pInput->numOfRows + pInput->startRowIndex; i += 1) {
411,089✔
5231
    if (pInfo->isPrevTsSet == true && tsList[i] == pInfo->prevTs) {
405,879!
5232
      return TSDB_CODE_FUNC_DUP_TIMESTAMP;
×
5233
    } else {
5234
      pInfo->prevTs = tsList[i];
405,879✔
5235
    }
5236

5237
    pInfo->isPrevTsSet = true;
405,879✔
5238
    numOfElems++;
405,879✔
5239

5240
    if (colDataIsNull_f(pInputCol->nullbitmap, i)) {
405,879✔
5241
      colDataSetNULL(pOutput, i);
238,278!
5242
      // handle selectivity
5243
      if (pCtx->subsidiaries.num > 0) {
238,278✔
5244
        code = appendSelectivityValue(pCtx, i, pCtx->offset + numOfElems - 1);
30✔
5245
        if (TSDB_CODE_SUCCESS != code) {
30!
5246
          return code;
×
5247
        }
5248
      }
5249
      continue;
238,278✔
5250
    }
5251

5252
    bool    ret = checkStateOp(op, pInputCol, i, pCtx->param[2].param);
167,601✔
5253
    int64_t output = -1;
167,601✔
5254
    if (ret) {
167,601✔
5255
      if (pInfo->durationStart == 0) {
140,116✔
5256
        output = 0;
14,292✔
5257
        pInfo->durationStart = tsList[i];
14,292✔
5258
      } else {
5259
        output = (tsList[i] - pInfo->durationStart) / timeUnit;
125,824✔
5260
      }
5261
    } else {
5262
      pInfo->durationStart = 0;
27,485✔
5263
    }
5264
    code = colDataSetVal(pOutput, pCtx->offset + numOfElems - 1, (char*)&output, false);
167,601✔
5265
    if (TSDB_CODE_SUCCESS != code) {
167,601!
5266
      return code;
×
5267
    }
5268

5269
    // handle selectivity
5270
    if (pCtx->subsidiaries.num > 0) {
167,601✔
5271
      code = appendSelectivityValue(pCtx, i, pCtx->offset + numOfElems - 1);
360✔
5272
      if (TSDB_CODE_SUCCESS != code) {
360!
5273
        return code;
×
5274
      }
5275
    }
5276
  }
5277

5278
  pResInfo->numOfRes = numOfElems;
5,210✔
5279
  return TSDB_CODE_SUCCESS;
5,210✔
5280
}
5281

5282
bool getCsumFuncEnv(SFunctionNode* UNUSED_PARAM(pFunc), SFuncExecEnv* pEnv) {
4,994✔
5283
  pEnv->calcMemSize = sizeof(SSumRes);
4,994✔
5284
  return true;
4,994✔
5285
}
5286

5287
int32_t csumFunction(SqlFunctionCtx* pCtx) {
5,534✔
5288
  int32_t              code = TSDB_CODE_SUCCESS;
5,534✔
5289
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
5,534✔
5290
  SSumRes*             pSumRes = GET_ROWCELL_INTERBUF(pResInfo);
5,534✔
5291

5292
  SInputColumnInfoData* pInput = &pCtx->input;
5,534✔
5293
  TSKEY*                tsList = (int64_t*)pInput->pPTS->pData;
5,534✔
5294

5295
  SColumnInfoData* pInputCol = pInput->pData[0];
5,534✔
5296
  SColumnInfoData* pOutput = (SColumnInfoData*)pCtx->pOutput;
5,534✔
5297

5298
  int32_t numOfElems = 0;
5,534✔
5299
  int32_t type = pInputCol->info.type;
5,534✔
5300
  int32_t startOffset = pCtx->offset;
5,534✔
5301
  for (int32_t i = pInput->startRowIndex; i < pInput->numOfRows + pInput->startRowIndex; i += 1) {
863,504✔
5302
    if (pSumRes->isPrevTsSet == true && tsList[i] == pSumRes->prevTs) {
857,922✔
5303
      return TSDB_CODE_FUNC_DUP_TIMESTAMP;
18✔
5304
    } else {
5305
      pSumRes->prevTs = tsList[i];
857,904✔
5306
    }
5307
    pSumRes->isPrevTsSet = true;
857,904✔
5308

5309
    int32_t pos = startOffset + numOfElems;
857,904✔
5310
    if (colDataIsNull_f(pInputCol->nullbitmap, i)) {
857,904✔
5311
      // colDataSetNULL(pOutput, i);
5312
      continue;
459,597✔
5313
    }
5314

5315
    char* data = colDataGetData(pInputCol, i);
398,307!
5316
    if (IS_SIGNED_NUMERIC_TYPE(type)) {
634,578!
5317
      int64_t v;
5318
      GET_TYPED_DATA(v, int64_t, type, data);
236,233!
5319
      pSumRes->isum += v;
236,233✔
5320
      code = colDataSetVal(pOutput, pos, (char*)&pSumRes->isum, false);
236,233✔
5321
      if (TSDB_CODE_SUCCESS != code) {
236,271!
5322
        return code;
×
5323
      }
5324
    } else if (IS_UNSIGNED_NUMERIC_TYPE(type)) {
162,584!
5325
      uint64_t v;
5326
      GET_TYPED_DATA(v, uint64_t, type, data);
510!
5327
      pSumRes->usum += v;
510✔
5328
      code = colDataSetVal(pOutput, pos, (char*)&pSumRes->usum, false);
510✔
5329
      if (TSDB_CODE_SUCCESS != code) {
510!
5330
        return code;
×
5331
      }
5332
    } else if (IS_FLOAT_TYPE(type)) {
161,564✔
5333
      double v;
5334
      GET_TYPED_DATA(v, double, type, data);
161,547!
5335
      pSumRes->dsum += v;
161,547✔
5336
      // check for overflow
5337
      if (isinf(pSumRes->dsum) || isnan(pSumRes->dsum)) {
161,547!
UNCOV
5338
        colDataSetNULL(pOutput, pos);
×
5339
      } else {
5340
        code = colDataSetVal(pOutput, pos, (char*)&pSumRes->dsum, false);
161,560✔
5341
        if (TSDB_CODE_SUCCESS != code) {
161,588!
5342
          return code;
×
5343
        }
5344
      }
5345
    }
5346

5347
    // handle selectivity
5348
    if (pCtx->subsidiaries.num > 0) {
398,373✔
5349
      code = appendSelectivityValue(pCtx, i, pos);
1,068✔
5350
      if (TSDB_CODE_SUCCESS != code) {
1,068!
5351
        return code;
×
5352
      }
5353
    }
5354

5355
    numOfElems++;
398,373✔
5356
  }
5357

5358
  pResInfo->numOfRes = numOfElems;
5,582✔
5359
  return TSDB_CODE_SUCCESS;
5,582✔
5360
}
5361

5362
bool getMavgFuncEnv(SFunctionNode* UNUSED_PARAM(pFunc), SFuncExecEnv* pEnv) {
3,732✔
5363
  pEnv->calcMemSize = sizeof(SMavgInfo) + MAVG_MAX_POINTS_NUM * sizeof(double);
3,732✔
5364
  return true;
3,732✔
5365
}
5366

5367
int32_t mavgFunctionSetup(SqlFunctionCtx* pCtx, SResultRowEntryInfo* pResultInfo) {
8,043✔
5368
  if (pResultInfo->initialized) {
8,043✔
5369
    return TSDB_CODE_SUCCESS;
3,630✔
5370
  }
5371
  if (TSDB_CODE_SUCCESS != functionSetup(pCtx, pResultInfo)) {
4,413!
5372
    return TSDB_CODE_FUNC_SETUP_ERROR;
×
5373
  }
5374

5375
  SMavgInfo* pInfo = GET_ROWCELL_INTERBUF(pResultInfo);
4,413✔
5376
  pInfo->pos = 0;
4,413✔
5377
  pInfo->sum = 0;
4,413✔
5378
  pInfo->prevTs = -1;
4,413✔
5379
  pInfo->isPrevTsSet = false;
4,413✔
5380
  pInfo->numOfPoints = pCtx->param[1].param.i;
4,413✔
5381
  if (pInfo->numOfPoints < 1 || pInfo->numOfPoints > MAVG_MAX_POINTS_NUM) {
4,413!
5382
    return TSDB_CODE_FUNC_FUNTION_PARA_VALUE;
×
5383
  }
5384
  pInfo->pointsMeet = false;
4,414✔
5385

5386
  return TSDB_CODE_SUCCESS;
4,414✔
5387
}
5388

5389
int32_t mavgFunction(SqlFunctionCtx* pCtx) {
4,310✔
5390
  int32_t              code = TSDB_CODE_SUCCESS;
4,310✔
5391
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
4,310✔
5392
  SMavgInfo*           pInfo = GET_ROWCELL_INTERBUF(pResInfo);
4,310✔
5393

5394
  SInputColumnInfoData* pInput = &pCtx->input;
4,310✔
5395
  TSKEY*                tsList = (int64_t*)pInput->pPTS->pData;
4,310✔
5396

5397
  SColumnInfoData* pInputCol = pInput->pData[0];
4,310✔
5398
  SColumnInfoData* pTsOutput = pCtx->pTsOutput;
4,310✔
5399
  SColumnInfoData* pOutput = (SColumnInfoData*)pCtx->pOutput;
4,310✔
5400

5401
  int32_t numOfElems = 0;
4,310✔
5402
  int32_t type = pInputCol->info.type;
4,310✔
5403
  int32_t startOffset = pCtx->offset;
4,310✔
5404
  for (int32_t i = pInput->startRowIndex; i < pInput->numOfRows + pInput->startRowIndex; i += 1) {
701,442✔
5405
    if (pInfo->isPrevTsSet == true && tsList[i] == pInfo->prevTs) {
697,129!
5406
      return TSDB_CODE_FUNC_DUP_TIMESTAMP;
×
5407
    } else {
5408
      pInfo->prevTs = tsList[i];
697,129✔
5409
    }
5410
    pInfo->isPrevTsSet = true;
697,129✔
5411

5412
    int32_t pos = startOffset + numOfElems;
697,129✔
5413
    if (colDataIsNull_f(pInputCol->nullbitmap, i)) {
697,129✔
5414
      // colDataSetNULL(pOutput, i);
5415
      continue;
430,458✔
5416
    }
5417

5418
    char*  data = colDataGetData(pInputCol, i);
266,671!
5419
    double v;
5420
    GET_TYPED_DATA(v, double, type, data);
266,671!
5421

5422
    if (!pInfo->pointsMeet && (pInfo->pos < pInfo->numOfPoints - 1)) {
266,671✔
5423
      pInfo->points[pInfo->pos] = v;
257,422✔
5424
      pInfo->sum += v;
257,422✔
5425
    } else {
5426
      if (!pInfo->pointsMeet && (pInfo->pos == pInfo->numOfPoints - 1)) {
9,249!
5427
        pInfo->sum += v;
608✔
5428
        pInfo->pointsMeet = true;
608✔
5429
      } else {
5430
        pInfo->sum = pInfo->sum + v - pInfo->points[pInfo->pos];
8,641✔
5431
      }
5432

5433
      pInfo->points[pInfo->pos] = v;
9,249✔
5434
      double result = pInfo->sum / pInfo->numOfPoints;
9,249✔
5435
      // check for overflow
5436
      if (isinf(result) || isnan(result)) {
9,249!
UNCOV
5437
        colDataSetNULL(pOutput, pos);
×
5438
      } else {
5439
        code = colDataSetVal(pOutput, pos, (char*)&result, false);
9,277✔
5440
        if (TSDB_CODE_SUCCESS != code) {
9,280!
5441
          return code;
×
5442
        }
5443
      }
5444

5445
      // handle selectivity
5446
      if (pCtx->subsidiaries.num > 0) {
9,252✔
5447
        code = appendSelectivityValue(pCtx, i, pos);
912✔
5448
        if (TSDB_CODE_SUCCESS != code) {
912!
5449
          return code;
×
5450
        }
5451
      }
5452

5453
      numOfElems++;
9,252✔
5454
    }
5455

5456
    pInfo->pos++;
266,674✔
5457
    if (pInfo->pos == pInfo->numOfPoints) {
266,674✔
5458
      pInfo->pos = 0;
950✔
5459
    }
5460
  }
5461

5462
  pResInfo->numOfRes = numOfElems;
4,313✔
5463
  return TSDB_CODE_SUCCESS;
4,313✔
5464
}
5465

5466
static SSampleInfo* getSampleOutputInfo(SqlFunctionCtx* pCtx) {
24,751✔
5467
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
24,751✔
5468
  SSampleInfo*         pInfo = GET_ROWCELL_INTERBUF(pResInfo);
24,751✔
5469

5470
  pInfo->data = (char*)pInfo + sizeof(SSampleInfo);
24,751✔
5471
  pInfo->tuplePos = (STuplePos*)((char*)pInfo + sizeof(SSampleInfo) + pInfo->samples * pInfo->colBytes);
24,751✔
5472

5473
  return pInfo;
24,751✔
5474
}
5475

5476
bool getSampleFuncEnv(SFunctionNode* pFunc, SFuncExecEnv* pEnv) {
5,819✔
5477
  SColumnNode* pCol = (SColumnNode*)nodesListGetNode(pFunc->pParameterList, 0);
5,819✔
5478
  SValueNode*  pVal = (SValueNode*)nodesListGetNode(pFunc->pParameterList, 1);
5,823✔
5479
  int32_t      numOfSamples = pVal->datum.i;
5,823✔
5480
  pEnv->calcMemSize = sizeof(SSampleInfo) + numOfSamples * (pCol->node.resType.bytes + sizeof(STuplePos));
5,823✔
5481
  return true;
5,823✔
5482
}
5483

5484
int32_t sampleFunctionSetup(SqlFunctionCtx* pCtx, SResultRowEntryInfo* pResultInfo) {
11,644✔
5485
  if (pResultInfo->initialized) {
11,644!
5486
    return TSDB_CODE_SUCCESS;
×
5487
  }
5488
  if (TSDB_CODE_SUCCESS != functionSetup(pCtx, pResultInfo)) {
11,644!
5489
    return TSDB_CODE_FUNC_SETUP_ERROR;
×
5490
  }
5491

5492
  taosSeedRand(taosSafeRand());
11,644✔
5493

5494
  SSampleInfo* pInfo = GET_ROWCELL_INTERBUF(pResultInfo);
11,644✔
5495
  pInfo->samples = pCtx->param[1].param.i;
11,644✔
5496
  pInfo->totalPoints = 0;
11,644✔
5497
  pInfo->numSampled = 0;
11,644✔
5498
  pInfo->colType = pCtx->resDataInfo.type;
11,644✔
5499
  pInfo->colBytes = pCtx->resDataInfo.bytes;
11,644✔
5500
  pInfo->nullTuplePos.pageId = -1;
11,644✔
5501
  pInfo->nullTupleSaved = false;
11,644✔
5502
  pInfo->data = (char*)pInfo + sizeof(SSampleInfo);
11,644✔
5503
  pInfo->tuplePos = (STuplePos*)((char*)pInfo + sizeof(SSampleInfo) + pInfo->samples * pInfo->colBytes);
11,644✔
5504

5505
  return TSDB_CODE_SUCCESS;
11,644✔
5506
}
5507

5508
static void sampleAssignResult(SSampleInfo* pInfo, char* data, int32_t index) {
474,103✔
5509
  assignVal(pInfo->data + index * pInfo->colBytes, data, pInfo->colBytes, pInfo->colType);
474,103✔
5510
}
474,093✔
5511

5512
static int32_t doReservoirSample(SqlFunctionCtx* pCtx, SSampleInfo* pInfo, char* data, int32_t index) {
498,173✔
5513
  pInfo->totalPoints++;
498,173✔
5514
  if (pInfo->numSampled < pInfo->samples) {
498,173✔
5515
    sampleAssignResult(pInfo, data, pInfo->numSampled);
447,944✔
5516
    if (pCtx->subsidiaries.num > 0) {
447,923✔
5517
      int32_t code = saveTupleData(pCtx, index, pCtx->pSrcBlock, &pInfo->tuplePos[pInfo->numSampled]);
6,210✔
5518
      if (code != TSDB_CODE_SUCCESS) {
6,270!
5519
        return code;
×
5520
      }
5521
    }
5522
    pInfo->numSampled++;
447,983✔
5523
  } else {
5524
    int32_t j = taosRand() % (pInfo->totalPoints);
50,229✔
5525
    if (j < pInfo->samples) {
50,235✔
5526
      sampleAssignResult(pInfo, data, j);
26,172✔
5527
      if (pCtx->subsidiaries.num > 0) {
26,172✔
5528
        int32_t code = updateTupleData(pCtx, index, pCtx->pSrcBlock, &pInfo->tuplePos[j]);
307✔
5529
        if (code != TSDB_CODE_SUCCESS) {
357!
5530
          return code;
×
5531
        }
5532
      }
5533
    }
5534
  }
5535

5536
  return TSDB_CODE_SUCCESS;
498,268✔
5537
}
5538

5539
int32_t sampleFunction(SqlFunctionCtx* pCtx) {
13,107✔
5540
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
13,107✔
5541
  SSampleInfo*         pInfo = getSampleOutputInfo(pCtx);
13,107✔
5542

5543
  SInputColumnInfoData* pInput = &pCtx->input;
13,107✔
5544

5545
  SColumnInfoData* pInputCol = pInput->pData[0];
13,107✔
5546
  for (int32_t i = pInput->startRowIndex; i < pInput->numOfRows + pInput->startRowIndex; i += 1) {
891,062✔
5547
    if (colDataIsNull_s(pInputCol, i)) {
1,753,640✔
5548
      continue;
379,750✔
5549
    }
5550

5551
    char*   data = colDataGetData(pInputCol, i);
497,070!
5552
    int32_t code = doReservoirSample(pCtx, pInfo, data, i);
497,070✔
5553
    if (code != TSDB_CODE_SUCCESS) {
498,205!
5554
      return code;
×
5555
    }
5556
  }
5557

5558
  if (pInfo->numSampled == 0 && pCtx->subsidiaries.num > 0 && !pInfo->nullTupleSaved) {
14,242✔
5559
    int32_t code = saveTupleData(pCtx, pInput->startRowIndex, pCtx->pSrcBlock, &pInfo->nullTuplePos);
21✔
5560
    if (code != TSDB_CODE_SUCCESS) {
21!
5561
      return code;
×
5562
    }
5563
    pInfo->nullTupleSaved = true;
21✔
5564
  }
5565

5566
  SET_VAL(pResInfo, pInfo->numSampled, pInfo->numSampled);
14,242✔
5567
  return TSDB_CODE_SUCCESS;
14,242✔
5568
}
5569

5570
int32_t sampleFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
11,644✔
5571
  int32_t              code = TSDB_CODE_SUCCESS;
11,644✔
5572
  SResultRowEntryInfo* pEntryInfo = GET_RES_INFO(pCtx);
11,644✔
5573

5574
  SSampleInfo* pInfo = getSampleOutputInfo(pCtx);
11,644✔
5575
  pEntryInfo->complete = true;
11,644✔
5576

5577
  int32_t          slotId = pCtx->pExpr->base.resSchema.slotId;
11,644✔
5578
  SColumnInfoData* pCol = taosArrayGet(pBlock->pDataBlock, slotId);
11,644✔
5579
  if (NULL == pCol) {
11,644!
5580
    return TSDB_CODE_OUT_OF_RANGE;
×
5581
  }
5582

5583
  int32_t currentRow = pBlock->info.rows;
11,644✔
5584
  if (pInfo->numSampled == 0) {
11,644✔
5585
    colDataSetNULL(pCol, currentRow);
2,272✔
5586
    code = setSelectivityValue(pCtx, pBlock, &pInfo->nullTuplePos, currentRow);
2,272✔
5587
    return code;
2,272✔
5588
  }
5589
  for (int32_t i = 0; i < pInfo->numSampled; ++i) {
457,304✔
5590
    code = colDataSetVal(pCol, currentRow + i, pInfo->data + i * pInfo->colBytes, false);
447,947✔
5591
    if (TSDB_CODE_SUCCESS != code) {
448,452!
5592
      return code;
×
5593
    }
5594
    code = setSelectivityValue(pCtx, pBlock, &pInfo->tuplePos[i], currentRow + i);
448,452✔
5595
    if (TSDB_CODE_SUCCESS != code) {
447,932!
5596
      return code;
×
5597
    }
5598
  }
5599

5600
  return code;
9,357✔
5601
}
5602

5603
bool getTailFuncEnv(SFunctionNode* pFunc, SFuncExecEnv* pEnv) {
×
5604
#if 0
5605
  SColumnNode* pCol = (SColumnNode*)nodesListGetNode(pFunc->pParameterList, 0);
5606
  SValueNode*  pVal = (SValueNode*)nodesListGetNode(pFunc->pParameterList, 1);
5607
  int32_t      numOfPoints = pVal->datum.i;
5608
  pEnv->calcMemSize = sizeof(STailInfo) + numOfPoints * (POINTER_BYTES + sizeof(STailItem) + pCol->node.resType.bytes);
5609
#endif
5610
  return true;
×
5611
}
5612

5613
int32_t tailFunctionSetup(SqlFunctionCtx* pCtx, SResultRowEntryInfo* pResultInfo) {
×
5614
#if 0
5615
  if (!functionSetup(pCtx, pResultInfo)) {
5616
    return false;
5617
  }
5618

5619
  STailInfo* pInfo = GET_ROWCELL_INTERBUF(pResultInfo);
5620
  pInfo->numAdded = 0;
5621
  pInfo->numOfPoints = pCtx->param[1].param.i;
5622
  if (pCtx->numOfParams == 4) {
5623
    pInfo->offset = pCtx->param[2].param.i;
5624
  } else {
5625
    pInfo->offset = 0;
5626
  }
5627
  pInfo->colType = pCtx->resDataInfo.type;
5628
  pInfo->colBytes = pCtx->resDataInfo.bytes;
5629
  if ((pInfo->numOfPoints < 1 || pInfo->numOfPoints > TAIL_MAX_POINTS_NUM) ||
5630
      (pInfo->numOfPoints < 0 || pInfo->numOfPoints > TAIL_MAX_OFFSET)) {
5631
    return false;
5632
  }
5633

5634
  pInfo->pItems = (STailItem**)((char*)pInfo + sizeof(STailInfo));
5635
  char* pItem = (char*)pInfo->pItems + pInfo->numOfPoints * POINTER_BYTES;
5636

5637
  size_t unitSize = sizeof(STailItem) + pInfo->colBytes;
5638
  for (int32_t i = 0; i < pInfo->numOfPoints; ++i) {
5639
    pInfo->pItems[i] = (STailItem*)(pItem + i * unitSize);
5640
    pInfo->pItems[i]->isNull = false;
5641
  }
5642
#endif
5643

5644
  return TSDB_CODE_SUCCESS;
×
5645
}
5646

5647
static void tailAssignResult(STailItem* pItem, char* data, int32_t colBytes, TSKEY ts, bool isNull) {
×
5648
#if 0
5649
  pItem->timestamp = ts;
5650
  if (isNull) {
5651
    pItem->isNull = true;
5652
  } else {
5653
    pItem->isNull = false;
5654
    memcpy(pItem->data, data, colBytes);
5655
  }
5656
#endif
5657
}
×
5658

5659
#if 0
5660
static int32_t tailCompFn(const void* p1, const void* p2, const void* param) {
5661
  STailItem* d1 = *(STailItem**)p1;
5662
  STailItem* d2 = *(STailItem**)p2;
5663
  return compareInt64Val(&d1->timestamp, &d2->timestamp);
5664
}
5665

5666
static void doTailAdd(STailInfo* pInfo, char* data, TSKEY ts, bool isNull) {
5667
  STailItem** pList = pInfo->pItems;
5668
  if (pInfo->numAdded < pInfo->numOfPoints) {
5669
    tailAssignResult(pList[pInfo->numAdded], data, pInfo->colBytes, ts, isNull);
5670
    taosheapsort((void*)pList, sizeof(STailItem**), pInfo->numAdded + 1, NULL, tailCompFn, 0);
5671
    pInfo->numAdded++;
5672
  } else if (pList[0]->timestamp < ts) {
5673
    tailAssignResult(pList[0], data, pInfo->colBytes, ts, isNull);
5674
    taosheapadjust((void*)pList, sizeof(STailItem**), 0, pInfo->numOfPoints - 1, NULL, tailCompFn, NULL, 0);
5675
  }
5676
}
5677
#endif
5678

5679
int32_t tailFunction(SqlFunctionCtx* pCtx) {
×
5680
#if 0
5681
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
5682
  STailInfo*           pInfo = GET_ROWCELL_INTERBUF(pResInfo);
5683

5684
  SInputColumnInfoData* pInput = &pCtx->input;
5685
  TSKEY*                tsList = (int64_t*)pInput->pPTS->pData;
5686

5687
  SColumnInfoData* pInputCol = pInput->pData[0];
5688
  SColumnInfoData* pOutput = (SColumnInfoData*)pCtx->pOutput;
5689

5690
  int32_t startOffset = pCtx->offset;
5691
  if (pInfo->offset >= pInput->numOfRows) {
5692
    return 0;
5693
  } else {
5694
    pInfo->numOfPoints = TMIN(pInfo->numOfPoints, pInput->numOfRows - pInfo->offset);
5695
  }
5696
  for (int32_t i = pInput->startRowIndex; i < pInput->numOfRows + pInput->startRowIndex - pInfo->offset; i += 1) {
5697
    char* data = colDataGetData(pInputCol, i);
5698
    doTailAdd(pInfo, data, tsList[i], colDataIsNull_s(pInputCol, i));
5699
  }
5700

5701
  taosqsort(pInfo->pItems, pInfo->numOfPoints, POINTER_BYTES, NULL, tailCompFn);
5702

5703
  for (int32_t i = 0; i < pInfo->numOfPoints; ++i) {
5704
    int32_t    pos = startOffset + i;
5705
    STailItem* pItem = pInfo->pItems[i];
5706
    if (pItem->isNull) {
5707
      colDataSetNULL(pOutput, pos);
5708
    } else {
5709
      colDataSetVal(pOutput, pos, pItem->data, false);
5710
    }
5711
  }
5712

5713
  return pInfo->numOfPoints;
5714
#endif
5715
  return 0;
×
5716
}
5717

5718
int32_t tailFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
×
5719
#if 0
5720
  SResultRowEntryInfo* pEntryInfo = GET_RES_INFO(pCtx);
5721
  STailInfo*           pInfo = GET_ROWCELL_INTERBUF(pEntryInfo);
5722
  pEntryInfo->complete = true;
5723

5724
  int32_t type = pCtx->input.pData[0]->info.type;
5725
  int32_t slotId = pCtx->pExpr->base.resSchema.slotId;
5726

5727
  SColumnInfoData* pCol = taosArrayGet(pBlock->pDataBlock, slotId);
5728

5729
  // todo assign the tag value and the corresponding row data
5730
  int32_t currentRow = pBlock->info.rows;
5731
  for (int32_t i = 0; i < pEntryInfo->numOfRes; ++i) {
5732
    STailItem* pItem = pInfo->pItems[i];
5733
    colDataSetVal(pCol, currentRow, pItem->data, false);
5734
    currentRow += 1;
5735
  }
5736

5737
  return pEntryInfo->numOfRes;
5738
#endif
5739
  return 0;
×
5740
}
5741

5742
bool getUniqueFuncEnv(SFunctionNode* pFunc, SFuncExecEnv* pEnv) {
×
5743
#if 0
5744
  pEnv->calcMemSize = sizeof(SUniqueInfo) + UNIQUE_MAX_RESULT_SIZE;
5745
#endif
5746
  return true;
×
5747
}
5748

5749
int32_t uniqueFunctionSetup(SqlFunctionCtx* pCtx, SResultRowEntryInfo* pResInfo) {
×
5750
#if 0
5751
  if (!functionSetup(pCtx, pResInfo)) {
5752
    return false;
5753
  }
5754

5755
  SUniqueInfo* pInfo = GET_ROWCELL_INTERBUF(pResInfo);
5756
  pInfo->numOfPoints = 0;
5757
  pInfo->colType = pCtx->resDataInfo.type;
5758
  pInfo->colBytes = pCtx->resDataInfo.bytes;
5759
  if (pInfo->pHash != NULL) {
5760
    taosHashClear(pInfo->pHash);
5761
  } else {
5762
    pInfo->pHash = taosHashInit(64, taosGetDefaultHashFunction(TSDB_DATA_TYPE_BINARY), true, HASH_NO_LOCK);
5763
  }
5764
#endif
5765
  return TSDB_CODE_SUCCESS;
×
5766
}
5767

5768
#if 0
5769
static void doUniqueAdd(SUniqueInfo* pInfo, char* data, TSKEY ts, bool isNull) {
5770
  // handle null elements
5771
  if (isNull == true) {
5772
    int32_t      size = sizeof(SUniqueItem) + pInfo->colBytes;
5773
    SUniqueItem* pItem = (SUniqueItem*)(pInfo->pItems + pInfo->numOfPoints * size);
5774
    if (pInfo->hasNull == false && pItem->isNull == false) {
5775
      pItem->timestamp = ts;
5776
      pItem->isNull = true;
5777
      pInfo->numOfPoints++;
5778
      pInfo->hasNull = true;
5779
    } else if (pItem->timestamp > ts && pItem->isNull == true) {
5780
      pItem->timestamp = ts;
5781
    }
5782
    return;
5783
  }
5784

5785
  int32_t      hashKeyBytes = IS_VAR_DATA_TYPE(pInfo->colType) ? varDataTLen(data) : pInfo->colBytes;
5786
  SUniqueItem* pHashItem = taosHashGet(pInfo->pHash, data, hashKeyBytes);
5787
  if (pHashItem == NULL) {
5788
    int32_t      size = sizeof(SUniqueItem) + pInfo->colBytes;
5789
    SUniqueItem* pItem = (SUniqueItem*)(pInfo->pItems + pInfo->numOfPoints * size);
5790
    pItem->timestamp = ts;
5791
    memcpy(pItem->data, data, pInfo->colBytes);
5792

5793
    taosHashPut(pInfo->pHash, data, hashKeyBytes, (char*)pItem, sizeof(SUniqueItem*));
5794
    pInfo->numOfPoints++;
5795
  } else if (pHashItem->timestamp > ts) {
5796
    pHashItem->timestamp = ts;
5797
  }
5798
}
5799
#endif
5800

5801
int32_t uniqueFunction(SqlFunctionCtx* pCtx) {
×
5802
#if 0
5803
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
5804
  SUniqueInfo*         pInfo = GET_ROWCELL_INTERBUF(pResInfo);
5805

5806
  SInputColumnInfoData* pInput = &pCtx->input;
5807
  TSKEY*                tsList = (int64_t*)pInput->pPTS->pData;
5808

5809
  SColumnInfoData* pInputCol = pInput->pData[0];
5810
  SColumnInfoData* pTsOutput = pCtx->pTsOutput;
5811
  SColumnInfoData* pOutput = (SColumnInfoData*)pCtx->pOutput;
5812

5813
  int32_t startOffset = pCtx->offset;
5814
  for (int32_t i = pInput->startRowIndex; i < pInput->numOfRows + pInput->startRowIndex; ++i) {
5815
    char* data = colDataGetData(pInputCol, i);
5816
    doUniqueAdd(pInfo, data, tsList[i], colDataIsNull_s(pInputCol, i));
5817

5818
    if (sizeof(SUniqueInfo) + pInfo->numOfPoints * (sizeof(SUniqueItem) + pInfo->colBytes) >= UNIQUE_MAX_RESULT_SIZE) {
5819
      taosHashCleanup(pInfo->pHash);
5820
      return 0;
5821
    }
5822
  }
5823

5824
  for (int32_t i = 0; i < pInfo->numOfPoints; ++i) {
5825
    SUniqueItem* pItem = (SUniqueItem*)(pInfo->pItems + i * (sizeof(SUniqueItem) + pInfo->colBytes));
5826
    if (pItem->isNull == true) {
5827
      colDataSetNULL(pOutput, i);
5828
    } else {
5829
      colDataSetVal(pOutput, i, pItem->data, false);
5830
    }
5831
    if (pTsOutput != NULL) {
5832
      colDataSetInt64(pTsOutput, i, &pItem->timestamp);
5833
    }
5834
  }
5835

5836
  return pInfo->numOfPoints;
5837
#endif
5838
  return 0;
×
5839
}
5840

5841
bool getModeFuncEnv(SFunctionNode* pFunc, SFuncExecEnv* pEnv) {
5,449✔
5842
  pEnv->calcMemSize = sizeof(SModeInfo);
5,449✔
5843
  return true;
5,449✔
5844
}
5845

5846
int32_t modeFunctionSetup(SqlFunctionCtx* pCtx, SResultRowEntryInfo* pResInfo) {
5,175✔
5847
  if (pResInfo->initialized) {
5,175!
5848
    return TSDB_CODE_SUCCESS;
×
5849
  }
5850
  if (TSDB_CODE_SUCCESS != functionSetup(pCtx, pResInfo)) {
5,175!
5851
    return TSDB_CODE_FUNC_SETUP_ERROR;
×
5852
  }
5853

5854
  SModeInfo* pInfo = GET_ROWCELL_INTERBUF(pResInfo);
5,175✔
5855
  pInfo->colType = pCtx->resDataInfo.type;
5,175✔
5856
  pInfo->colBytes = pCtx->resDataInfo.bytes;
5,175✔
5857
  if (pInfo->pHash != NULL) {
5,175!
5858
    taosHashClear(pInfo->pHash);
×
5859
  } else {
5860
    pInfo->pHash = taosHashInit(64, taosGetDefaultHashFunction(TSDB_DATA_TYPE_BINARY), true, HASH_NO_LOCK);
5,175✔
5861
    if (NULL == pInfo->pHash) {
5,175!
5862
      return terrno;
×
5863
    }
5864
  }
5865
  pInfo->nullTupleSaved = false;
5,175✔
5866
  pInfo->nullTuplePos.pageId = -1;
5,175✔
5867

5868
  pInfo->buf = taosMemoryMalloc(pInfo->colBytes);
5,175!
5869
  if (NULL == pInfo->buf) {
5,175!
5870
    taosHashCleanup(pInfo->pHash);
×
5871
    pInfo->pHash = NULL;
×
5872
    return terrno;
×
5873
  }
5874
  pCtx->needCleanup = true;
5,175✔
5875
  return TSDB_CODE_SUCCESS;
5,175✔
5876
}
5877

5878
static void modeFunctionCleanup(SModeInfo* pInfo) {
5,175✔
5879
  taosHashCleanup(pInfo->pHash);
5,175✔
5880
  pInfo->pHash = NULL;
5,175✔
5881
  taosMemoryFreeClear(pInfo->buf);
5,175!
5882
}
5,175✔
5883

5884
void modeFunctionCleanupExt(SqlFunctionCtx* pCtx) {
×
5885
  if (pCtx == NULL || GET_RES_INFO(pCtx) == NULL || GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx)) == NULL) {
×
5886
    return;
×
5887
  }
5888
  modeFunctionCleanup(GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx)));
×
5889
}
5890

5891
static int32_t saveModeTupleData(SqlFunctionCtx* pCtx, char* data, SModeInfo* pInfo, STuplePos* pPos) {
444,381✔
5892
  if (IS_VAR_DATA_TYPE(pInfo->colType)) {
444,381!
5893
    if (pInfo->colType == TSDB_DATA_TYPE_JSON) {
51!
5894
      (void)memcpy(pInfo->buf, data, getJsonValueLen(data));
×
5895
    } else {
5896
      (void)memcpy(pInfo->buf, data, varDataTLen(data));
51✔
5897
    }
5898
  } else {
5899
    (void)memcpy(pInfo->buf, data, pInfo->colBytes);
444,330✔
5900
  }
5901

5902
  return doSaveTupleData(&pCtx->saveHandle, pInfo->buf, pInfo->colBytes, NULL, pPos, pCtx->pStore);
444,381✔
5903
}
5904

5905
static int32_t doModeAdd(SModeInfo* pInfo, int32_t rowIndex, SqlFunctionCtx* pCtx, char* data) {
550,828✔
5906
  int32_t code = TSDB_CODE_SUCCESS;
550,828✔
5907
  int32_t hashKeyBytes;
5908
  if (IS_VAR_DATA_TYPE(pInfo->colType)) {
550,828✔
5909
    if (pInfo->colType == TSDB_DATA_TYPE_JSON) {
185!
5910
      hashKeyBytes = getJsonValueLen(data);
×
5911
    } else {
5912
      hashKeyBytes = varDataTLen(data);
185✔
5913
    }
5914
  } else {
5915
    hashKeyBytes = pInfo->colBytes;
550,643✔
5916
  }
5917

5918
  SModeItem* pHashItem = (SModeItem*)taosHashGet(pInfo->pHash, data, hashKeyBytes);
550,727✔
5919
  if (pHashItem == NULL) {
548,864✔
5920
    int32_t   size = sizeof(SModeItem);
444,266✔
5921
    SModeItem item = {0};
444,266✔
5922

5923
    item.count += 1;
444,266✔
5924
    code = saveModeTupleData(pCtx, data, pInfo, &item.dataPos);
444,266✔
5925
    if (code != TSDB_CODE_SUCCESS) {
442,670!
5926
      return code;
×
5927
    }
5928

5929
    if (pCtx->subsidiaries.num > 0) {
442,670✔
5930
      code = saveTupleData(pCtx, rowIndex, pCtx->pSrcBlock, &item.tuplePos);
309✔
5931
      if (code != TSDB_CODE_SUCCESS) {
309!
5932
        return code;
×
5933
      }
5934
    }
5935

5936
    code = taosHashPut(pInfo->pHash, data, hashKeyBytes, &item, sizeof(SModeItem));
442,670✔
5937
    if (code != TSDB_CODE_SUCCESS) {
447,243!
5938
      return code;
×
5939
    }
5940
  } else {
5941
    pHashItem->count += 1;
104,598✔
5942
    if (pCtx->subsidiaries.num > 0) {
104,598✔
5943
      code = updateTupleData(pCtx, rowIndex, pCtx->pSrcBlock, &pHashItem->tuplePos);
105✔
5944
      if (code != TSDB_CODE_SUCCESS) {
105!
5945
        return code;
×
5946
      }
5947
    }
5948
  }
5949

5950
  return code;
551,841✔
5951
}
5952

5953
int32_t modeFunction(SqlFunctionCtx* pCtx) {
6,207✔
5954
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
6,207✔
5955
  SModeInfo*           pInfo = GET_ROWCELL_INTERBUF(pResInfo);
6,207✔
5956

5957
  SInputColumnInfoData* pInput = &pCtx->input;
6,207✔
5958

5959
  SColumnInfoData* pInputCol = pInput->pData[0];
6,207✔
5960
  SColumnInfoData* pOutput = (SColumnInfoData*)pCtx->pOutput;
6,207✔
5961

5962
  int32_t numOfElems = 0;
6,207✔
5963
  int32_t startOffset = pCtx->offset;
6,207✔
5964
  for (int32_t i = pInput->startRowIndex; i < pInput->numOfRows + pInput->startRowIndex; ++i) {
930,743✔
5965
    if (colDataIsNull_s(pInputCol, i)) {
1,848,388✔
5966
      continue;
373,093✔
5967
    }
5968
    numOfElems++;
551,101✔
5969

5970
    char*   data = colDataGetData(pInputCol, i);
551,101!
5971
    int32_t code = doModeAdd(pInfo, i, pCtx, data);
551,101✔
5972
    if (code != TSDB_CODE_SUCCESS) {
551,811✔
5973
      modeFunctionCleanup(pInfo);
368✔
5974
      return code;
×
5975
    }
5976
  }
5977

5978
  if (numOfElems == 0 && pCtx->subsidiaries.num > 0 && !pInfo->nullTupleSaved) {
6,549!
5979
    int32_t code = saveTupleData(pCtx, pInput->startRowIndex, pCtx->pSrcBlock, &pInfo->nullTuplePos);
30✔
5980
    if (code != TSDB_CODE_SUCCESS) {
30!
5981
      modeFunctionCleanup(pInfo);
×
5982
      return code;
×
5983
    }
5984
    pInfo->nullTupleSaved = true;
30✔
5985
  }
5986

5987
  SET_VAL(pResInfo, numOfElems, 1);
6,549✔
5988

5989
  return TSDB_CODE_SUCCESS;
6,549✔
5990
}
5991

5992
int32_t modeFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
5,175✔
5993
  int32_t              code = TSDB_CODE_SUCCESS;
5,175✔
5994
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
5,175✔
5995
  SModeInfo*           pInfo = GET_ROWCELL_INTERBUF(pResInfo);
5,175✔
5996
  int32_t              slotId = pCtx->pExpr->base.resSchema.slotId;
5,175✔
5997
  SColumnInfoData*     pCol = taosArrayGet(pBlock->pDataBlock, slotId);
5,175✔
5998
  int32_t              currentRow = pBlock->info.rows;
5,175✔
5999
  if (NULL == pCol) {
5,175!
6000
    modeFunctionCleanup(pInfo);
×
6001
    return TSDB_CODE_OUT_OF_RANGE;
×
6002
  }
6003

6004
  STuplePos resDataPos, resTuplePos;
6005
  int32_t   maxCount = 0;
5,175✔
6006

6007
  void* pIter = taosHashIterate(pInfo->pHash, NULL);
5,175✔
6008
  while (pIter != NULL) {
452,445✔
6009
    SModeItem* pItem = (SModeItem*)pIter;
447,270✔
6010
    if (pItem->count >= maxCount) {
447,270✔
6011
      maxCount = pItem->count;
380,687✔
6012
      resDataPos = pItem->dataPos;
380,687✔
6013
      resTuplePos = pItem->tuplePos;
380,687✔
6014
    }
6015

6016
    pIter = taosHashIterate(pInfo->pHash, pIter);
447,270✔
6017
  }
6018

6019
  if (maxCount != 0) {
5,175✔
6020
    char* pData = NULL;
3,120✔
6021
    code = loadTupleData(pCtx, &resDataPos, &pData);
3,120✔
6022
    if (pData == NULL || TSDB_CODE_SUCCESS != code) {
3,120!
6023
      code = terrno = TSDB_CODE_NOT_FOUND;
×
6024
      qError("Load tuple data failed since %s, groupId:%" PRIu64 ", ts:%" PRId64, terrstr(),
×
6025
             resDataPos.streamTupleKey.groupId, resDataPos.streamTupleKey.ts);
6026
      modeFunctionCleanup(pInfo);
×
6027
      return code;
×
6028
    }
6029

6030
    code = colDataSetVal(pCol, currentRow, pData, false);
3,120✔
6031
    if (TSDB_CODE_SUCCESS != code) {
3,120!
6032
      modeFunctionCleanup(pInfo);
×
6033
      return code;
×
6034
    }
6035
    code = setSelectivityValue(pCtx, pBlock, &resTuplePos, currentRow);
3,120✔
6036
  } else {
6037
    colDataSetNULL(pCol, currentRow);
2,055✔
6038
    code = setSelectivityValue(pCtx, pBlock, &pInfo->nullTuplePos, currentRow);
2,055✔
6039
  }
6040

6041
  modeFunctionCleanup(pInfo);
5,175✔
6042

6043
  return code;
5,175✔
6044
}
6045

6046
bool getTwaFuncEnv(struct SFunctionNode* pFunc, SFuncExecEnv* pEnv) {
3,355✔
6047
  pEnv->calcMemSize = sizeof(STwaInfo);
3,355✔
6048
  return true;
3,355✔
6049
}
6050

6051
int32_t twaFunctionSetup(SqlFunctionCtx* pCtx, SResultRowEntryInfo* pResultInfo) {
42,552✔
6052
  if (pResultInfo->initialized) {
42,552!
6053
    return TSDB_CODE_SUCCESS;
×
6054
  }
6055
  if (TSDB_CODE_SUCCESS != functionSetup(pCtx, pResultInfo)) {
42,552!
6056
    return TSDB_CODE_FUNC_SETUP_ERROR;
×
6057
  }
6058

6059
  STwaInfo* pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
42,551✔
6060
  pInfo->numOfElems = 0;
42,551✔
6061
  pInfo->p.key = INT64_MIN;
42,551✔
6062
  pInfo->win = TSWINDOW_INITIALIZER;
42,551✔
6063
  return TSDB_CODE_SUCCESS;
42,551✔
6064
}
6065

6066
static double twa_get_area(SPoint1 s, SPoint1 e) {
458,667✔
6067
  if (e.key == INT64_MAX || s.key == INT64_MIN) {
458,667!
6068
    return 0;
×
6069
  }
6070

6071
  if ((s.val >= 0 && e.val >= 0) || (s.val <= 0 && e.val <= 0)) {
458,816✔
6072
    return (s.val + e.val) * (e.key - s.key) / 2;
375,776✔
6073
  }
6074

6075
  double x = (s.key * e.val - e.key * s.val) / (e.val - s.val);
83,040✔
6076
  double val = (s.val * (x - s.key) + e.val * (e.key - x)) / 2;
83,040✔
6077
  return val;
83,040✔
6078
}
6079

6080
int32_t twaFunction(SqlFunctionCtx* pCtx) {
43,037✔
6081
  int32_t               code = TSDB_CODE_SUCCESS;
43,037✔
6082
  SInputColumnInfoData* pInput = &pCtx->input;
43,037✔
6083
  SColumnInfoData*      pInputCol = pInput->pData[0];
43,037✔
6084

6085
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
43,037✔
6086
  STwaInfo*            pInfo = GET_ROWCELL_INTERBUF(pResInfo);
43,037✔
6087
  SPoint1*             last = &pInfo->p;
43,037✔
6088

6089
  if (IS_NULL_TYPE(pInputCol->info.type)) {
43,037!
6090
    pInfo->numOfElems = 0;
×
6091
    goto _twa_over;
×
6092
  }
6093

6094
  funcInputUpdate(pCtx);
43,037✔
6095
  SFuncInputRow row = {0};
43,039✔
6096
  bool          result = false;
43,039✔
6097
  if (pCtx->start.key != INT64_MIN && last->key == INT64_MIN) {
43,039!
6098
    while (1) {
6099
      code = funcInputGetNextRow(pCtx, &row, &result);
13,361✔
6100
      if (TSDB_CODE_SUCCESS != code) {
13,361!
6101
        return code;
×
6102
      }
6103
      if (!result) {
13,361✔
6104
        break;
2✔
6105
      }
6106
      if (row.isDataNull) {
13,359✔
6107
        continue;
2✔
6108
      }
6109

6110
      last->key = row.ts;
13,357✔
6111

6112
      GET_TYPED_DATA(last->val, double, pInputCol->info.type, row.pData);
13,357!
6113

6114
      pInfo->dOutput += twa_get_area(pCtx->start, *last);
13,357✔
6115
      pInfo->win.skey = pCtx->start.key;
13,357✔
6116
      pInfo->numOfElems++;
13,357✔
6117
      break;
13,357✔
6118
    }
6119
  } else if (pInfo->p.key == INT64_MIN) {
29,680✔
6120
    while (1) {
6121
      code = funcInputGetNextRow(pCtx, &row, &result);
142,725✔
6122
      if (TSDB_CODE_SUCCESS != code) {
142,723!
6123
        return code;
×
6124
      }
6125
      if (!result) {
142,723✔
6126
        break;
14,181✔
6127
      }
6128
      if (row.isDataNull) {
128,542✔
6129
        continue;
113,292✔
6130
      }
6131

6132
      last->key = row.ts;
15,250✔
6133

6134
      GET_TYPED_DATA(last->val, double, pInputCol->info.type, row.pData);
15,250!
6135

6136
      pInfo->win.skey = last->key;
15,250✔
6137
      pInfo->numOfElems++;
15,250✔
6138
      break;
15,250✔
6139
    }
6140
  }
6141

6142
  SPoint1 st = {0};
43,037✔
6143

6144
  // calculate the value of
6145
  while (1) {
6146
    code = funcInputGetNextRow(pCtx, &row, &result);
475,572✔
6147
    if (TSDB_CODE_SUCCESS != code) {
475,843!
6148
      return code;
×
6149
    }
6150
    if (!result) {
475,843✔
6151
      break;
43,040✔
6152
    }
6153
    if (row.isDataNull) {
432,803✔
6154
      continue;
378✔
6155
    }
6156
    pInfo->numOfElems++;
432,425✔
6157
    switch (pInputCol->info.type) {
432,425✔
6158
      case TSDB_DATA_TYPE_TINYINT: {
56,565✔
6159
        INIT_INTP_POINT(st, row.ts, *(int8_t*)row.pData);
56,565✔
6160
        break;
56,565✔
6161
      }
6162
      case TSDB_DATA_TYPE_SMALLINT: {
59,413✔
6163
        INIT_INTP_POINT(st, row.ts, *(int16_t*)row.pData);
59,413✔
6164
        break;
59,413✔
6165
      }
6166
      case TSDB_DATA_TYPE_INT: {
72,884✔
6167
        INIT_INTP_POINT(st, row.ts, *(int32_t*)row.pData);
72,884✔
6168
        break;
72,884✔
6169
      }
6170
      case TSDB_DATA_TYPE_BIGINT: {
53,548✔
6171
        INIT_INTP_POINT(st, row.ts, *(int64_t*)row.pData);
53,548✔
6172
        break;
53,548✔
6173
      }
6174
      case TSDB_DATA_TYPE_FLOAT: {
34,342✔
6175
        INIT_INTP_POINT(st, row.ts, *(float_t*)row.pData);
34,342✔
6176
        break;
34,342✔
6177
      }
6178
      case TSDB_DATA_TYPE_DOUBLE: {
42,723✔
6179
        INIT_INTP_POINT(st, row.ts, *(double*)row.pData);
42,723✔
6180
        break;
42,723✔
6181
      }
6182
      case TSDB_DATA_TYPE_UTINYINT: {
29,493✔
6183
        INIT_INTP_POINT(st, row.ts, *(uint8_t*)row.pData);
29,493✔
6184
        break;
29,493✔
6185
      }
6186
      case TSDB_DATA_TYPE_USMALLINT: {
28,849✔
6187
        INIT_INTP_POINT(st, row.ts, *(uint16_t*)row.pData);
28,849✔
6188
        break;
28,849✔
6189
      }
6190
      case TSDB_DATA_TYPE_UINT: {
31,137✔
6191
        INIT_INTP_POINT(st, row.ts, *(uint32_t*)row.pData);
31,137✔
6192
        break;
31,137✔
6193
      }
6194
      case TSDB_DATA_TYPE_UBIGINT: {
23,147✔
6195
        INIT_INTP_POINT(st, row.ts, *(uint64_t*)row.pData);
23,147✔
6196
        break;
23,147✔
6197
      }
6198
      default: {
324✔
6199
        return TSDB_CODE_FUNC_FUNTION_PARA_TYPE;
324✔
6200
      }
6201
    }
6202
    if (pInfo->p.key == st.key) {
432,101!
6203
      return TSDB_CODE_FUNC_DUP_TIMESTAMP;
×
6204
    }
6205

6206
    pInfo->dOutput += twa_get_area(pInfo->p, st);
432,101✔
6207
    pInfo->p = st;
432,157✔
6208
  }
6209

6210
  // the last interpolated time window value
6211
  if (pCtx->end.key != INT64_MIN) {
43,040✔
6212
    pInfo->dOutput += twa_get_area(pInfo->p, pCtx->end);
13,364✔
6213
    pInfo->p = pCtx->end;
13,364✔
6214
    pInfo->numOfElems += 1;
13,364✔
6215
  }
6216

6217
  pInfo->win.ekey = pInfo->p.key;
43,040✔
6218

6219
_twa_over:
43,040✔
6220
  SET_VAL(pResInfo, 1, 1);
43,040✔
6221
  return TSDB_CODE_SUCCESS;
43,040✔
6222
}
6223

6224
/*
6225
 * To copy the input to interResBuf to avoid the input buffer space be over writen
6226
 * by next input data. The TWA function only applies to each table, so no merge procedure
6227
 * is required, we simply copy to the resut ot interResBuffer.
6228
 */
6229
// void twa_function_copy(SQLFunctionCtx *pCtx) {
6230
//   SResultRowEntryInfo *pResInfo = GET_RES_INFO(pCtx);
6231
//
6232
//   memcpy(GET_ROWCELL_INTERBUF(pResInfo), pCtx->pInput, (size_t)pCtx->inputBytes);
6233
//   pResInfo->hasResult = ((STwaInfo *)pCtx->pInput)->hasResult;
6234
// }
6235

6236
int32_t twaFinalize(struct SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
42,664✔
6237
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
42,664✔
6238

6239
  STwaInfo* pInfo = (STwaInfo*)GET_ROWCELL_INTERBUF(pResInfo);
42,664✔
6240
  if (pInfo->numOfElems == 0) {
42,664✔
6241
    pResInfo->numOfRes = 0;
13,941✔
6242
  } else {
6243
    if (pInfo->win.ekey == pInfo->win.skey) {
28,723✔
6244
      pInfo->dTwaRes = pInfo->p.val;
10,236✔
6245
    } else if (pInfo->win.ekey == INT64_MAX || pInfo->win.skey == INT64_MIN) {  // no data in timewindow
18,487!
6246
      pInfo->dTwaRes = 0;
2✔
6247
    } else {
6248
      pInfo->dTwaRes = pInfo->dOutput / (pInfo->win.ekey - pInfo->win.skey);
18,485✔
6249
    }
6250

6251
    pResInfo->numOfRes = 1;
28,723✔
6252
  }
6253

6254
  return functionFinalize(pCtx, pBlock);
42,664✔
6255
}
6256

6257
int32_t blockDistSetup(SqlFunctionCtx* pCtx, SResultRowEntryInfo* pResultInfo) {
4✔
6258
  if (pResultInfo->initialized) {
4!
6259
    return TSDB_CODE_SUCCESS;
×
6260
  }
6261
  if (TSDB_CODE_SUCCESS != functionSetup(pCtx, pResultInfo)) {
4!
6262
    return TSDB_CODE_FUNC_SETUP_ERROR;
×
6263
  }
6264

6265
  STableBlockDistInfo* pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
4✔
6266
  pInfo->minRows = INT32_MAX;
4✔
6267
  return TSDB_CODE_SUCCESS;
4✔
6268
}
6269

6270
int32_t blockDistFunction(SqlFunctionCtx* pCtx) {
6✔
6271
  const int32_t BLOCK_DIST_RESULT_ROWS = 25;
6✔
6272

6273
  SInputColumnInfoData* pInput = &pCtx->input;
6✔
6274
  SColumnInfoData*      pInputCol = pInput->pData[0];
6✔
6275
  SResultRowEntryInfo*  pResInfo = GET_RES_INFO(pCtx);
6✔
6276
  STableBlockDistInfo*  pDistInfo = GET_ROWCELL_INTERBUF(pResInfo);
6✔
6277

6278
  STableBlockDistInfo p1 = {0};
6✔
6279
  if (tDeserializeBlockDistInfo(varDataVal(pInputCol->pData), varDataLen(pInputCol->pData), &p1) < 0) {
6!
6280
    qError("failed to deserialize block dist info");
×
6281
    return TSDB_CODE_FAILED;
×
6282
  }
6283

6284
  pDistInfo->numOfBlocks += p1.numOfBlocks;
6✔
6285
  pDistInfo->numOfTables += p1.numOfTables;
6✔
6286
  pDistInfo->numOfInmemRows += p1.numOfInmemRows;
6✔
6287
  pDistInfo->numOfSttRows += p1.numOfSttRows;
6✔
6288
  pDistInfo->totalSize += p1.totalSize;
6✔
6289
  pDistInfo->totalRows += p1.totalRows;
6✔
6290
  pDistInfo->numOfFiles += p1.numOfFiles;
6✔
6291

6292
  pDistInfo->defMinRows = p1.defMinRows;
6✔
6293
  pDistInfo->defMaxRows = p1.defMaxRows;
6✔
6294
  pDistInfo->rowSize = p1.rowSize;
6✔
6295

6296
  if (pDistInfo->minRows > p1.minRows) {
6✔
6297
    pDistInfo->minRows = p1.minRows;
1✔
6298
  }
6299
  if (pDistInfo->maxRows < p1.maxRows) {
6✔
6300
    pDistInfo->maxRows = p1.maxRows;
1✔
6301
  }
6302
  pDistInfo->numOfVgroups += (p1.numOfTables != 0 ? 1 : 0);
6✔
6303
  for (int32_t i = 0; i < tListLen(pDistInfo->blockRowsHisto); ++i) {
126✔
6304
    pDistInfo->blockRowsHisto[i] += p1.blockRowsHisto[i];
120✔
6305
  }
6306

6307
  pResInfo->numOfRes = BLOCK_DIST_RESULT_ROWS;  // default output rows
6✔
6308
  return TSDB_CODE_SUCCESS;
6✔
6309
}
6310

6311
int32_t tSerializeBlockDistInfo(void* buf, int32_t bufLen, const STableBlockDistInfo* pInfo) {
12✔
6312
  SEncoder encoder = {0};
12✔
6313
  int32_t  code = 0;
12✔
6314
  int32_t  lino;
6315
  int32_t  tlen;
6316
  tEncoderInit(&encoder, buf, bufLen);
12✔
6317

6318
  TAOS_CHECK_EXIT(tStartEncode(&encoder));
12!
6319
  TAOS_CHECK_EXIT(tEncodeU32(&encoder, pInfo->rowSize));
24!
6320

6321
  TAOS_CHECK_EXIT(tEncodeU16(&encoder, pInfo->numOfFiles));
24!
6322
  TAOS_CHECK_EXIT(tEncodeU32(&encoder, pInfo->numOfBlocks));
24!
6323
  TAOS_CHECK_EXIT(tEncodeU32(&encoder, pInfo->numOfTables));
24!
6324

6325
  TAOS_CHECK_EXIT(tEncodeU64(&encoder, pInfo->totalSize));
24!
6326
  TAOS_CHECK_EXIT(tEncodeU64(&encoder, pInfo->totalRows));
24!
6327
  TAOS_CHECK_EXIT(tEncodeI32(&encoder, pInfo->maxRows));
24!
6328
  TAOS_CHECK_EXIT(tEncodeI32(&encoder, pInfo->minRows));
24!
6329
  TAOS_CHECK_EXIT(tEncodeI32(&encoder, pInfo->defMaxRows));
24!
6330
  TAOS_CHECK_EXIT(tEncodeI32(&encoder, pInfo->defMinRows));
24!
6331
  TAOS_CHECK_EXIT(tEncodeU32(&encoder, pInfo->numOfInmemRows));
24!
6332
  TAOS_CHECK_EXIT(tEncodeU32(&encoder, pInfo->numOfSttRows));
24!
6333
  TAOS_CHECK_EXIT(tEncodeU32(&encoder, pInfo->numOfVgroups));
24!
6334

6335
  for (int32_t i = 0; i < tListLen(pInfo->blockRowsHisto); ++i) {
252✔
6336
    TAOS_CHECK_EXIT(tEncodeI32(&encoder, pInfo->blockRowsHisto[i]));
480!
6337
  }
6338

6339
  tEndEncode(&encoder);
12✔
6340

6341
_exit:
12✔
6342
  if (code) {
12!
6343
    tlen = code;
×
6344
  } else {
6345
    tlen = encoder.pos;
12✔
6346
  }
6347
  tEncoderClear(&encoder);
12✔
6348
  return tlen;
12✔
6349
}
6350

6351
int32_t tDeserializeBlockDistInfo(void* buf, int32_t bufLen, STableBlockDistInfo* pInfo) {
6✔
6352
  SDecoder decoder = {0};
6✔
6353
  int32_t  code = 0;
6✔
6354
  int32_t  lino;
6355
  tDecoderInit(&decoder, buf, bufLen);
6✔
6356

6357
  TAOS_CHECK_EXIT(tStartDecode(&decoder));
6!
6358
  TAOS_CHECK_EXIT(tDecodeU32(&decoder, &pInfo->rowSize));
12!
6359

6360
  TAOS_CHECK_EXIT(tDecodeU16(&decoder, &pInfo->numOfFiles));
12!
6361
  TAOS_CHECK_EXIT(tDecodeU32(&decoder, &pInfo->numOfBlocks));
12!
6362
  TAOS_CHECK_EXIT(tDecodeU32(&decoder, &pInfo->numOfTables));
12!
6363

6364
  TAOS_CHECK_EXIT(tDecodeU64(&decoder, &pInfo->totalSize));
12!
6365
  TAOS_CHECK_EXIT(tDecodeU64(&decoder, &pInfo->totalRows));
12!
6366
  TAOS_CHECK_EXIT(tDecodeI32(&decoder, &pInfo->maxRows));
12!
6367
  TAOS_CHECK_EXIT(tDecodeI32(&decoder, &pInfo->minRows));
12!
6368
  TAOS_CHECK_EXIT(tDecodeI32(&decoder, &pInfo->defMaxRows));
12!
6369
  TAOS_CHECK_EXIT(tDecodeI32(&decoder, &pInfo->defMinRows));
12!
6370
  TAOS_CHECK_EXIT(tDecodeU32(&decoder, &pInfo->numOfInmemRows));
12!
6371
  TAOS_CHECK_EXIT(tDecodeU32(&decoder, &pInfo->numOfSttRows));
12!
6372
  TAOS_CHECK_EXIT(tDecodeU32(&decoder, &pInfo->numOfVgroups));
12!
6373

6374
  for (int32_t i = 0; i < tListLen(pInfo->blockRowsHisto); ++i) {
126✔
6375
    TAOS_CHECK_EXIT(tDecodeI32(&decoder, &pInfo->blockRowsHisto[i]));
240!
6376
  }
6377

6378
_exit:
6✔
6379
  tDecoderClear(&decoder);
6✔
6380
  return code;
6✔
6381
}
6382

6383
int32_t blockDistFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
4✔
6384
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
4✔
6385
  STableBlockDistInfo* pData = GET_ROWCELL_INTERBUF(pResInfo);
4✔
6386

6387
  SColumnInfoData* pColInfo = taosArrayGet(pBlock->pDataBlock, 0);
4✔
6388
  if (NULL == pColInfo) {
4!
6389
    return TSDB_CODE_OUT_OF_RANGE;
×
6390
  }
6391

6392
  if (pData->totalRows == 0) {
4✔
6393
    pData->minRows = 0;
3✔
6394
  }
6395

6396
  int32_t row = 0;
4✔
6397
  char    st[256] = {0};
4✔
6398
  double  averageSize = 0;
4✔
6399
  if (pData->numOfBlocks != 0) {
4✔
6400
    averageSize = ((double)pData->totalSize) / pData->numOfBlocks;
1✔
6401
  }
6402
  uint64_t totalRawSize = pData->totalRows * pData->rowSize;
4✔
6403
  double   compRatio = 0;
4✔
6404
  if (totalRawSize != 0) {
4✔
6405
    compRatio = pData->totalSize * 100 / (double)totalRawSize;
1✔
6406
  }
6407

6408
  int32_t len = tsnprintf(varDataVal(st), sizeof(st) - VARSTR_HEADER_SIZE,
8✔
6409
                          "Total_Blocks=[%d] Total_Size=[%.2f KiB] Average_size=[%.2f KiB] Compression_Ratio=[%.2f %c]",
6410
                          pData->numOfBlocks, pData->totalSize / 1024.0, averageSize / 1024.0, compRatio, '%');
4✔
6411

6412
  varDataSetLen(st, len);
4✔
6413
  int32_t code = colDataSetVal(pColInfo, row++, st, false);
4✔
6414
  if (TSDB_CODE_SUCCESS != code) {
4!
6415
    return code;
×
6416
  }
6417

6418
  int64_t avgRows = 0;
4✔
6419
  if (pData->numOfBlocks > 0) {
4✔
6420
    avgRows = pData->totalRows / pData->numOfBlocks;
1✔
6421
  }
6422

6423
  len = tsnprintf(varDataVal(st), sizeof(st) - VARSTR_HEADER_SIZE,
4✔
6424
                  "Block_Rows=[%" PRId64 "] MinRows=[%d] MaxRows=[%d] AvgRows=[%" PRId64 "]", pData->totalRows,
6425
                  pData->minRows, pData->maxRows, avgRows);
6426
  varDataSetLen(st, len);
4✔
6427
  code = colDataSetVal(pColInfo, row++, st, false);
4✔
6428
  if (TSDB_CODE_SUCCESS != code) {
4!
6429
    return code;
×
6430
  }
6431

6432
  len = tsnprintf(varDataVal(st), sizeof(st) - VARSTR_HEADER_SIZE, "Inmem_Rows=[%d] Stt_Rows=[%d] ",
4✔
6433
                  pData->numOfInmemRows, pData->numOfSttRows);
6434
  varDataSetLen(st, len);
4✔
6435
  code = colDataSetVal(pColInfo, row++, st, false);
4✔
6436
  if (TSDB_CODE_SUCCESS != code) {
4!
6437
    return code;
×
6438
  }
6439

6440
  len = tsnprintf(varDataVal(st), sizeof(st) - VARSTR_HEADER_SIZE,
8✔
6441
                  "Total_Tables=[%d] Total_Filesets=[%d] Total_Vgroups=[%d]", pData->numOfTables, pData->numOfFiles,
4✔
6442
                  pData->numOfVgroups);
6443

6444
  varDataSetLen(st, len);
4✔
6445
  code = colDataSetVal(pColInfo, row++, st, false);
4✔
6446
  if (TSDB_CODE_SUCCESS != code) {
4!
6447
    return code;
×
6448
  }
6449

6450
  len = tsnprintf(varDataVal(st), sizeof(st) - VARSTR_HEADER_SIZE,
4✔
6451
                  "--------------------------------------------------------------------------------");
6452
  varDataSetLen(st, len);
4✔
6453
  code = colDataSetVal(pColInfo, row++, st, false);
4✔
6454
  if (TSDB_CODE_SUCCESS != code) {
4!
6455
    return code;
×
6456
  }
6457

6458
  int32_t maxVal = 0;
4✔
6459
  int32_t minVal = INT32_MAX;
4✔
6460
  for (int32_t i = 0; i < tListLen(pData->blockRowsHisto); ++i) {
84✔
6461
    if (maxVal < pData->blockRowsHisto[i]) {
80✔
6462
      maxVal = pData->blockRowsHisto[i];
1✔
6463
    }
6464

6465
    if (minVal > pData->blockRowsHisto[i]) {
80✔
6466
      minVal = pData->blockRowsHisto[i];
5✔
6467
    }
6468
  }
6469

6470
  // maximum number of step is 80
6471
  double factor = pData->numOfBlocks / 80.0;
4✔
6472

6473
  int32_t numOfBuckets = sizeof(pData->blockRowsHisto) / sizeof(pData->blockRowsHisto[0]);
4✔
6474
  int32_t bucketRange = ceil(((double)(pData->defMaxRows - pData->defMinRows)) / numOfBuckets);
4✔
6475

6476
  for (int32_t i = 0; i < tListLen(pData->blockRowsHisto); ++i) {
84✔
6477
    len =
80✔
6478
        tsnprintf(varDataVal(st), sizeof(st) - VARSTR_HEADER_SIZE, "%04d |", pData->defMinRows + bucketRange * (i + 1));
80✔
6479

6480
    int32_t num = 0;
80✔
6481
    if (pData->blockRowsHisto[i] > 0) {
80✔
6482
      num = (pData->blockRowsHisto[i]) / factor;
1✔
6483
    }
6484

6485
    for (int32_t j = 0; j < num; ++j) {
160✔
6486
      int32_t x = tsnprintf(varDataVal(st) + len, sizeof(st) - VARSTR_HEADER_SIZE - len, "%c", '|');
80✔
6487
      len += x;
80✔
6488
    }
6489

6490
    if (pData->blockRowsHisto[i] > 0) {
80✔
6491
      double v = pData->blockRowsHisto[i] * 100.0 / pData->numOfBlocks;
1✔
6492
      len += tsnprintf(varDataVal(st) + len, sizeof(st) - VARSTR_HEADER_SIZE - len, "  %d (%.2f%c)",
1✔
6493
                       pData->blockRowsHisto[i], v, '%');
6494
    }
6495

6496
    varDataSetLen(st, len);
80✔
6497
    code = colDataSetVal(pColInfo, row++, st, false);
80✔
6498
    if (TSDB_CODE_SUCCESS != code) {
80!
6499
      return code;
×
6500
    }
6501
  }
6502

6503
  return TSDB_CODE_SUCCESS;
4✔
6504
}
6505
int32_t blockDBUsageSetup(SqlFunctionCtx* pCtx, SResultRowEntryInfo* pResultInfo) {
1✔
6506
  if (pResultInfo->initialized) {
1!
6507
    return TSDB_CODE_SUCCESS;
×
6508
  }
6509
  if (TSDB_CODE_SUCCESS != functionSetup(pCtx, pResultInfo)) {
1!
6510
    return TSDB_CODE_FUNC_SETUP_ERROR;
×
6511
  }
6512

6513
  SDBBlockUsageInfo* pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
1✔
6514
  return TSDB_CODE_SUCCESS;
1✔
6515
}
6516
int32_t blockDBUsageFunction(SqlFunctionCtx* pCtx) {
2✔
6517
  const int32_t BLOCK_DISK_USAGE_RESULT_ROWS = 2;
2✔
6518

6519
  SInputColumnInfoData* pInput = &pCtx->input;
2✔
6520
  SColumnInfoData*      pInputCol = pInput->pData[0];
2✔
6521
  SResultRowEntryInfo*  pResInfo = GET_RES_INFO(pCtx);
2✔
6522
  SDBBlockUsageInfo*    pDistInfo = GET_ROWCELL_INTERBUF(pResInfo);
2✔
6523

6524
  SDBBlockUsageInfo p1 = {0};
2✔
6525
  if (tDeserializeBlockDbUsage(varDataVal(pInputCol->pData), varDataLen(pInputCol->pData), &p1) < 0) {
2!
6526
    qError("failed to deserialize block dist info");
×
6527
    return TSDB_CODE_FAILED;
×
6528
  }
6529

6530
  pDistInfo->dataInDiskSize += p1.dataInDiskSize;
2✔
6531
  pDistInfo->walInDiskSize += p1.walInDiskSize;
2✔
6532
  pDistInfo->rawDataSize += p1.rawDataSize;
2✔
6533
  pResInfo->numOfRes = BLOCK_DISK_USAGE_RESULT_ROWS;  // default output rows
2✔
6534
  return TSDB_CODE_SUCCESS;
2✔
6535
}
6536

6537
int32_t tSerializeBlockDbUsage(void* buf, int32_t bufLen, const SDBBlockUsageInfo* pInfo) {
4✔
6538
  SEncoder encoder = {0};
4✔
6539
  int32_t  code = 0;
4✔
6540
  int32_t  lino;
6541
  int32_t  tlen;
6542
  tEncoderInit(&encoder, buf, bufLen);
4✔
6543

6544
  TAOS_CHECK_EXIT(tStartEncode(&encoder));
4!
6545

6546
  TAOS_CHECK_EXIT(tEncodeU64(&encoder, pInfo->dataInDiskSize));
8!
6547
  TAOS_CHECK_EXIT(tEncodeU64(&encoder, pInfo->walInDiskSize));
8!
6548
  TAOS_CHECK_EXIT(tEncodeU64(&encoder, pInfo->rawDataSize));
8!
6549

6550
  tEndEncode(&encoder);
4✔
6551

6552
_exit:
4✔
6553
  if (code) {
4!
6554
    tlen = code;
×
6555
  } else {
6556
    tlen = encoder.pos;
4✔
6557
  }
6558
  tEncoderClear(&encoder);
4✔
6559
  return tlen;
4✔
6560
}
6561
int32_t tDeserializeBlockDbUsage(void* buf, int32_t bufLen, SDBBlockUsageInfo* pInfo) {
2✔
6562
  SDecoder decoder = {0};
2✔
6563
  int32_t  code = 0;
2✔
6564
  int32_t  lino;
6565
  tDecoderInit(&decoder, buf, bufLen);
2✔
6566

6567
  TAOS_CHECK_EXIT(tStartDecode(&decoder));
2!
6568
  TAOS_CHECK_EXIT(tDecodeU64(&decoder, &pInfo->dataInDiskSize));
4!
6569
  TAOS_CHECK_EXIT(tDecodeU64(&decoder, &pInfo->walInDiskSize));
4!
6570
  TAOS_CHECK_EXIT(tDecodeU64(&decoder, &pInfo->rawDataSize));
4!
6571

6572
_exit:
2✔
6573
  tDecoderClear(&decoder);
2✔
6574
  return code;
2✔
6575
}
6576
int32_t blockDBUsageFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
1✔
6577
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
1✔
6578
  SDBBlockUsageInfo*   pData = GET_ROWCELL_INTERBUF(pResInfo);
1✔
6579

6580
  SColumnInfoData* pColInfo = taosArrayGet(pBlock->pDataBlock, 0);
1✔
6581
  if (NULL == pColInfo) {
1!
6582
    return TSDB_CODE_OUT_OF_RANGE;
×
6583
  }
6584
  int32_t len = 0;
1✔
6585
  int32_t row = 0;
1✔
6586
  char    st[256] = {0};
1✔
6587

6588
  uint64_t totalDiskSize = pData->dataInDiskSize;
1✔
6589
  uint64_t rawDataSize = pData->rawDataSize;
1✔
6590
  double   compressRadio = 0;
1✔
6591
  if (rawDataSize != 0) {
1!
6592
    compressRadio = totalDiskSize * 100 / (double)rawDataSize;
1✔
6593
    len = tsnprintf(varDataVal(st), sizeof(st) - VARSTR_HEADER_SIZE, "Compress_radio=[%.2f]", compressRadio);
1✔
6594
  } else {
6595
    len = tsnprintf(varDataVal(st), sizeof(st) - VARSTR_HEADER_SIZE, "Compress_radio=[NULL]");
×
6596
  }
6597

6598
  varDataSetLen(st, len);
1✔
6599
  int32_t code = colDataSetVal(pColInfo, row++, st, false);
1✔
6600
  if (TSDB_CODE_SUCCESS != code) {
1!
6601
    return code;
×
6602
  }
6603

6604
  len =
1✔
6605
      tsnprintf(varDataVal(st), sizeof(st) - VARSTR_HEADER_SIZE, "Disk_occupied=[%" PRId64 "k]", pData->dataInDiskSize);
1✔
6606
  varDataSetLen(st, len);
1✔
6607
  code = colDataSetVal(pColInfo, row++, st, false);
1✔
6608
  if (TSDB_CODE_SUCCESS != code) {
1!
6609
    return code;
×
6610
  }
6611
  return code;
1✔
6612
}
6613

6614
bool getDerivativeFuncEnv(struct SFunctionNode* pFunc, SFuncExecEnv* pEnv) {
653✔
6615
  pEnv->calcMemSize = sizeof(SDerivInfo);
653✔
6616
  return true;
653✔
6617
}
6618

6619
int32_t derivativeFuncSetup(SqlFunctionCtx* pCtx, SResultRowEntryInfo* pResInfo) {
1,405✔
6620
  if (pResInfo->initialized) {
1,405✔
6621
    return TSDB_CODE_SUCCESS;
651✔
6622
  }
6623
  if (TSDB_CODE_SUCCESS != functionSetup(pCtx, pResInfo)) {
754!
6624
    return TSDB_CODE_FUNC_SETUP_ERROR;
×
6625
  }
6626

6627
  SDerivInfo* pDerivInfo = GET_ROWCELL_INTERBUF(pResInfo);
754✔
6628

6629
  pDerivInfo->ignoreNegative = pCtx->param[2].param.i;
754✔
6630
  pDerivInfo->prevTs = -1;
754✔
6631
  pDerivInfo->tsWindow = pCtx->param[1].param.i;
754✔
6632
  pDerivInfo->valueSet = false;
754✔
6633
  return TSDB_CODE_SUCCESS;
754✔
6634
}
6635

6636
int32_t derivativeFunction(SqlFunctionCtx* pCtx) {
752✔
6637
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
752✔
6638
  SDerivInfo*          pDerivInfo = GET_ROWCELL_INTERBUF(pResInfo);
752✔
6639

6640
  SInputColumnInfoData* pInput = &pCtx->input;
752✔
6641
  SColumnInfoData*      pInputCol = pInput->pData[0];
752✔
6642

6643
  int32_t          numOfElems = 0;
752✔
6644
  SColumnInfoData* pOutput = (SColumnInfoData*)pCtx->pOutput;
752✔
6645
  SColumnInfoData* pTsOutput = pCtx->pTsOutput;
752✔
6646
  int32_t          code = TSDB_CODE_SUCCESS;
752✔
6647

6648
  funcInputUpdate(pCtx);
752✔
6649

6650
  double v = 0;
752✔
6651
  if (pCtx->order == TSDB_ORDER_ASC) {
752✔
6652
    SFuncInputRow row = {0};
720✔
6653
    bool          result = false;
720✔
6654
    while (1) {
71,842✔
6655
      code = funcInputGetNextRow(pCtx, &row, &result);
72,562✔
6656
      if (TSDB_CODE_SUCCESS != code) {
72,562!
6657
        return code;
×
6658
      }
6659
      if (!result) {
72,562✔
6660
        break;
720✔
6661
      }
6662
      if (row.isDataNull) {
71,842✔
6663
        continue;
33,557✔
6664
      }
6665

6666
      char* d = row.pData;
38,285✔
6667
      GET_TYPED_DATA(v, double, pInputCol->info.type, d);
38,285!
6668

6669
      int32_t pos = pCtx->offset + numOfElems;
38,285✔
6670
      if (!pDerivInfo->valueSet) {  // initial value is not set yet
38,285✔
6671
        pDerivInfo->valueSet = true;
379✔
6672
      } else {
6673
        if (row.ts == pDerivInfo->prevTs) {
37,906!
6674
          return TSDB_CODE_FUNC_DUP_TIMESTAMP;
×
6675
        }
6676
        double r = ((v - pDerivInfo->prevValue) * pDerivInfo->tsWindow) / (row.ts - pDerivInfo->prevTs);
37,906✔
6677
        if (pDerivInfo->ignoreNegative && r < 0) {
37,906✔
6678
        } else {
6679
          if (isinf(r) || isnan(r)) {
29,961!
6680
            colDataSetNULL(pOutput, pos);
×
6681
          } else {
6682
            code = colDataSetVal(pOutput, pos, (const char*)&r, false);
29,961✔
6683
            if (code != TSDB_CODE_SUCCESS) {
29,961!
6684
              return code;
×
6685
            }
6686
          }
6687

6688
          if (pTsOutput != NULL) {
29,961!
6689
            colDataSetInt64(pTsOutput, pos, &row.ts);
×
6690
          }
6691

6692
          // handle selectivity
6693
          if (pCtx->subsidiaries.num > 0) {
29,961✔
6694
            code = appendSelectivityCols(pCtx, row.block, row.rowIndex, pos);
332✔
6695
            if (code != TSDB_CODE_SUCCESS) {
332!
6696
              return code;
×
6697
            }
6698
          }
6699

6700
          numOfElems++;
29,961✔
6701
        }
6702
      }
6703

6704
      pDerivInfo->prevValue = v;
38,285✔
6705
      pDerivInfo->prevTs = row.ts;
38,285✔
6706
    }
6707
  } else {
6708
    SFuncInputRow row = {0};
32✔
6709
    bool          result = false;
32✔
6710
    while (1) {
118✔
6711
      code = funcInputGetNextRow(pCtx, &row, &result);
150✔
6712
      if (TSDB_CODE_SUCCESS != code) {
150!
6713
        return code;
×
6714
      }
6715
      if (!result) {
150✔
6716
        break;
32✔
6717
      }
6718
      if (row.isDataNull) {
118✔
6719
        continue;
42✔
6720
      }
6721

6722
      char* d = row.pData;
76✔
6723
      GET_TYPED_DATA(v, double, pInputCol->info.type, d);
76!
6724

6725
      int32_t pos = pCtx->offset + numOfElems;
76✔
6726
      if (!pDerivInfo->valueSet) {  // initial value is not set yet
76✔
6727
        pDerivInfo->valueSet = true;
11✔
6728
      } else {
6729
        if (row.ts == pDerivInfo->prevTs) {
65!
6730
          return TSDB_CODE_FUNC_DUP_TIMESTAMP;
×
6731
        }
6732
        double r = ((pDerivInfo->prevValue - v) * pDerivInfo->tsWindow) / (pDerivInfo->prevTs - row.ts);
65✔
6733
        if (pDerivInfo->ignoreNegative && r < 0) {
65!
6734
        } else {
6735
          if (isinf(r) || isnan(r)) {
57!
6736
            colDataSetNULL(pOutput, pos);
×
6737
          } else {
6738
            code = colDataSetVal(pOutput, pos, (const char*)&r, false);
57✔
6739
            if (code != TSDB_CODE_SUCCESS) {
57!
6740
              return code;
×
6741
            }
6742
          }
6743

6744
          if (pTsOutput != NULL) {
57!
6745
            colDataSetInt64(pTsOutput, pos, &pDerivInfo->prevTs);
×
6746
          }
6747

6748
          // handle selectivity
6749
          if (pCtx->subsidiaries.num > 0) {
57!
6750
            code = appendSelectivityCols(pCtx, row.block, row.rowIndex, pos);
×
6751
            if (code != TSDB_CODE_SUCCESS) {
×
6752
              return code;
×
6753
            }
6754
          }
6755
          numOfElems++;
57✔
6756
        }
6757
      }
6758

6759
      pDerivInfo->prevValue = v;
76✔
6760
      pDerivInfo->prevTs = row.ts;
76✔
6761
    }
6762
  }
6763

6764
  pResInfo->numOfRes = numOfElems;
752✔
6765

6766
  return TSDB_CODE_SUCCESS;
752✔
6767
}
6768

6769
int32_t getIrateInfoSize(int32_t pkBytes) { return (int32_t)sizeof(SRateInfo) + 2 * pkBytes; }
2,382✔
6770

6771
bool getIrateFuncEnv(struct SFunctionNode* pFunc, SFuncExecEnv* pEnv) {
2,131✔
6772
  int32_t pkBytes = (pFunc->hasPk) ? pFunc->pkBytes : 0;
2,131✔
6773
  pEnv->calcMemSize = getIrateInfoSize(pkBytes);
2,131✔
6774
  return true;
2,134✔
6775
}
6776

6777
int32_t irateFuncSetup(SqlFunctionCtx* pCtx, SResultRowEntryInfo* pResInfo) {
27,471✔
6778
  if (pResInfo->initialized) {
27,471!
6779
    return TSDB_CODE_SUCCESS;
×
6780
  }
6781
  if (TSDB_CODE_SUCCESS != functionSetup(pCtx, pResInfo)) {
27,471!
6782
    return TSDB_CODE_FUNC_SETUP_ERROR;
×
6783
  }
6784

6785
  SRateInfo* pInfo = GET_ROWCELL_INTERBUF(pResInfo);
27,471✔
6786

6787
  pInfo->firstKey = INT64_MIN;
27,471✔
6788
  pInfo->lastKey = INT64_MIN;
27,471✔
6789
  pInfo->firstValue = (double)INT64_MIN;
27,471✔
6790
  pInfo->lastValue = (double)INT64_MIN;
27,471✔
6791

6792
  pInfo->hasResult = 0;
27,471✔
6793
  return TSDB_CODE_SUCCESS;
27,471✔
6794
}
6795

6796
static void doSaveRateInfo(SRateInfo* pRateInfo, bool isFirst, int64_t ts, char* pk, double v) {
255,742✔
6797
  if (isFirst) {
255,742✔
6798
    pRateInfo->firstValue = v;
121,065✔
6799
    pRateInfo->firstKey = ts;
121,065✔
6800
    if (pRateInfo->firstPk) {
121,065✔
6801
      int32_t pkBytes;
6802
      if (IS_VAR_DATA_TYPE(pRateInfo->pkType)) {
35!
6803
        if (pRateInfo->pkType == TSDB_DATA_TYPE_JSON) {
8!
6804
          pkBytes = getJsonValueLen(pk);
×
6805
        } else {
6806
          pkBytes = varDataTLen(pk);
8✔
6807
        }
6808
      } else {
6809
        pkBytes = pRateInfo->pkBytes;
27✔
6810
      }
6811
      (void)memcpy(pRateInfo->firstPk, pk, pkBytes);
35✔
6812
    }
6813
  } else {
6814
    pRateInfo->lastValue = v;
134,677✔
6815
    pRateInfo->lastKey = ts;
134,677✔
6816
    if (pRateInfo->lastPk) {
134,677✔
6817
      int32_t pkBytes;
6818
      if (IS_VAR_DATA_TYPE(pRateInfo->pkType)) {
52!
6819
        if (pRateInfo->pkType == TSDB_DATA_TYPE_JSON) {
12!
6820
          pkBytes = getJsonValueLen(pk);
×
6821
        } else {
6822
          pkBytes = varDataTLen(pk);
12✔
6823
        }
6824
      } else {
6825
        pkBytes = pRateInfo->pkBytes;
40✔
6826
      }
6827
      (void)memcpy(pRateInfo->lastPk, pk, pkBytes);
52✔
6828
    }
6829
  }
6830
}
255,742✔
6831

6832
static void initializeRateInfo(SqlFunctionCtx* pCtx, SRateInfo* pRateInfo, bool isMerge) {
28,828✔
6833
  if (pCtx->hasPrimaryKey) {
28,828✔
6834
    if (!isMerge) {
19✔
6835
      pRateInfo->pkType = pCtx->input.pPrimaryKey->info.type;
17✔
6836
      pRateInfo->pkBytes = pCtx->input.pPrimaryKey->info.bytes;
17✔
6837
      pRateInfo->firstPk = pRateInfo->pkData;
17✔
6838
      pRateInfo->lastPk = pRateInfo->pkData + pRateInfo->pkBytes;
17✔
6839
    } else {
6840
      pRateInfo->firstPk = pRateInfo->pkData;
2✔
6841
      pRateInfo->lastPk = pRateInfo->pkData + pRateInfo->pkBytes;
2✔
6842
    }
6843
  } else {
6844
    pRateInfo->firstPk = NULL;
28,809✔
6845
    pRateInfo->lastPk = NULL;
28,809✔
6846
  }
6847
}
28,828✔
6848

6849
int32_t irateFunction(SqlFunctionCtx* pCtx) {
28,456✔
6850
  int32_t              code = TSDB_CODE_SUCCESS;
28,456✔
6851
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
28,456✔
6852
  SRateInfo*           pRateInfo = GET_ROWCELL_INTERBUF(pResInfo);
28,456✔
6853

6854
  SInputColumnInfoData* pInput = &pCtx->input;
28,456✔
6855
  SColumnInfoData*      pInputCol = pInput->pData[0];
28,456✔
6856

6857
  SColumnInfoData* pOutput = (SColumnInfoData*)pCtx->pOutput;
28,456✔
6858

6859
  funcInputUpdate(pCtx);
28,456✔
6860

6861
  initializeRateInfo(pCtx, pRateInfo, false);
28,456✔
6862

6863
  int32_t       numOfElems = 0;
28,456✔
6864
  int32_t       type = pInputCol->info.type;
28,456✔
6865
  SFuncInputRow row = {0};
28,456✔
6866
  bool          result = false;
28,456✔
6867
  while (1) {
256,235✔
6868
    code = funcInputGetNextRow(pCtx, &row, &result);
284,691✔
6869
    if (TSDB_CODE_SUCCESS != code) {
284,692!
6870
      return code;
×
6871
    }
6872
    if (!result) {
284,692✔
6873
      break;
28,456✔
6874
    }
6875
    if (row.isDataNull) {
256,236✔
6876
      continue;
119,366✔
6877
    }
6878

6879
    char*  data = row.pData;
136,870✔
6880
    double v = 0;
136,870✔
6881
    GET_TYPED_DATA(v, double, type, data);
136,870!
6882

6883
    if (INT64_MIN == pRateInfo->lastKey) {
136,870✔
6884
      doSaveRateInfo(pRateInfo, false, row.ts, row.pPk, v);
13,673✔
6885
      pRateInfo->hasResult = 1;
13,673✔
6886
      continue;
13,673✔
6887
    }
6888

6889
    if (row.ts > pRateInfo->lastKey) {
123,197✔
6890
      if ((INT64_MIN == pRateInfo->firstKey) || pRateInfo->lastKey > pRateInfo->firstKey) {
120,816!
6891
        doSaveRateInfo(pRateInfo, true, pRateInfo->lastKey, pRateInfo->lastPk, pRateInfo->lastValue);
120,816✔
6892
      }
6893
      doSaveRateInfo(pRateInfo, false, row.ts, row.pPk, v);
120,816✔
6894
      continue;
120,813✔
6895
    } else if (row.ts == pRateInfo->lastKey) {
2,381!
6896
      return TSDB_CODE_FUNC_DUP_TIMESTAMP;
×
6897
    }
6898

6899
    if ((INT64_MIN == pRateInfo->firstKey) || row.ts > pRateInfo->firstKey) {
2,381!
6900
      doSaveRateInfo(pRateInfo, true, row.ts, row.pPk, v);
13✔
6901
    } else if (row.ts == pRateInfo->firstKey) {
2,368!
6902
      return TSDB_CODE_FUNC_DUP_TIMESTAMP;
×
6903
    }
6904
  }
6905

6906
  numOfElems++;
28,456✔
6907

6908
  SET_VAL(pResInfo, numOfElems, 1);
28,456!
6909
  return TSDB_CODE_SUCCESS;
28,456✔
6910
}
6911

6912
static double doCalcRate(const SRateInfo* pRateInfo, double tickPerSec) {
27,285✔
6913
  if ((INT64_MIN == pRateInfo->lastKey) || (INT64_MIN == pRateInfo->firstKey) ||
27,285✔
6914
      (pRateInfo->firstKey >= pRateInfo->lastKey)) {
1,226!
6915
    return 0.0;
26,059✔
6916
  }
6917

6918
  double diff = 0;
1,226✔
6919
  // If the previous value of the last is greater than the last value, only keep the last point instead of the delta
6920
  // value between two values.
6921
  diff = pRateInfo->lastValue;
1,226✔
6922
  if (diff >= pRateInfo->firstValue) {
1,226✔
6923
    diff -= pRateInfo->firstValue;
569✔
6924
  }
6925

6926
  int64_t duration = pRateInfo->lastKey - pRateInfo->firstKey;
1,226✔
6927
  if (duration == 0) {
1,226!
6928
    return 0;
×
6929
  }
6930

6931
  return (duration > 0) ? ((double)diff) / (duration / tickPerSec) : 0.0;
1,226!
6932
}
6933

6934
static void irateTransferInfoImpl(TSKEY inputKey, SRateInfo* pInput, SRateInfo* pOutput, bool isFirstKey) {
174✔
6935
  if (inputKey > pOutput->lastKey) {
174✔
6936
    doSaveRateInfo(pOutput, true, pOutput->lastKey, pOutput->lastPk, pOutput->lastValue);
120✔
6937
    if (isFirstKey) {
120✔
6938
      doSaveRateInfo(pOutput, false, pInput->firstKey, pInput->firstPk, pInput->firstValue);
56✔
6939
    } else {
6940
      doSaveRateInfo(pOutput, false, pInput->lastKey, pInput->lastPk, pInput->lastValue);
64✔
6941
    }
6942
  } else if ((inputKey < pOutput->lastKey) && (inputKey > pOutput->firstKey)) {
54!
6943
    if (isFirstKey) {
20✔
6944
      doSaveRateInfo(pOutput, true, pInput->firstKey, pInput->firstPk, pInput->firstValue);
10✔
6945
    } else {
6946
      doSaveRateInfo(pOutput, true, pInput->lastKey, pInput->lastPk, pInput->lastValue);
10✔
6947
    }
6948
  } else {
6949
    // inputKey < pOutput->firstKey
6950
  }
6951
}
174✔
6952

6953
static void irateCopyInfo(SRateInfo* pInput, SRateInfo* pOutput) {
93✔
6954
  doSaveRateInfo(pOutput, true, pInput->firstKey, pInput->firstPk, pInput->firstValue);
93✔
6955
  doSaveRateInfo(pOutput, false, pInput->lastKey, pInput->lastPk, pInput->lastValue);
93✔
6956
}
93✔
6957

6958
static int32_t irateTransferInfo(SRateInfo* pInput, SRateInfo* pOutput) {
180✔
6959
  if ((pInput->firstKey != INT64_MIN &&
180✔
6960
       (pInput->firstKey == pOutput->firstKey || pInput->firstKey == pOutput->lastKey)) ||
175!
6961
      (pInput->lastKey != INT64_MIN && (pInput->lastKey == pOutput->firstKey || pInput->lastKey == pOutput->lastKey))) {
180!
6962
    return TSDB_CODE_FUNC_DUP_TIMESTAMP;
×
6963
  }
6964

6965
  if (pOutput->hasResult == 0) {
180✔
6966
    irateCopyInfo(pInput, pOutput);
93✔
6967
    pOutput->hasResult = pInput->hasResult;
93✔
6968
    return TSDB_CODE_SUCCESS;
93✔
6969
  }
6970

6971
  if (pInput->firstKey != INT64_MIN) {
87!
6972
    irateTransferInfoImpl(pInput->firstKey, pInput, pOutput, true);
87✔
6973
  }
6974

6975
  if (pInput->lastKey != INT64_MIN) {
87!
6976
    irateTransferInfoImpl(pInput->lastKey, pInput, pOutput, false);
87✔
6977
  }
6978

6979
  pOutput->hasResult = pInput->hasResult;
87✔
6980
  return TSDB_CODE_SUCCESS;
87✔
6981
}
6982

6983
int32_t irateFunctionMerge(SqlFunctionCtx* pCtx) {
186✔
6984
  SInputColumnInfoData* pInput = &pCtx->input;
186✔
6985
  SColumnInfoData*      pCol = pInput->pData[0];
186✔
6986
  if (pCol->info.type != TSDB_DATA_TYPE_BINARY) {
186!
6987
    return TSDB_CODE_FUNC_FUNTION_PARA_TYPE;
×
6988
  }
6989

6990
  SRateInfo* pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
186✔
6991
  initializeRateInfo(pCtx, pInfo, true);
186✔
6992

6993
  int32_t start = pInput->startRowIndex;
186✔
6994
  for (int32_t i = start; i < start + pInput->numOfRows; ++i) {
372✔
6995
    char*      data = colDataGetData(pCol, i);
186!
6996
    SRateInfo* pInputInfo = (SRateInfo*)varDataVal(data);
186✔
6997
    initializeRateInfo(pCtx, pInfo, true);
186✔
6998
    if (pInputInfo->hasResult) {
186✔
6999
      int32_t code = irateTransferInfo(pInputInfo, pInfo);
180✔
7000
      if (code != TSDB_CODE_SUCCESS) {
180!
7001
        return code;
×
7002
      }
7003
    }
7004
  }
7005

7006
  if (pInfo->hasResult) {
186✔
7007
    GET_RES_INFO(pCtx)->numOfRes = 1;
180✔
7008
  }
7009

7010
  return TSDB_CODE_SUCCESS;
186✔
7011
}
7012

7013
int32_t iratePartialFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
186✔
7014
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
186✔
7015
  SRateInfo*           pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
186✔
7016
  int32_t              resultBytes = getIrateInfoSize(pInfo->pkBytes);
186✔
7017
  char*                res = taosMemoryCalloc(resultBytes + VARSTR_HEADER_SIZE, sizeof(char));
186!
7018

7019
  if (NULL == res) {
186!
7020
    return terrno;
×
7021
  }
7022
  (void)memcpy(varDataVal(res), pInfo, resultBytes);
186✔
7023
  varDataSetLen(res, resultBytes);
186✔
7024

7025
  int32_t          slotId = pCtx->pExpr->base.resSchema.slotId;
186✔
7026
  SColumnInfoData* pCol = taosArrayGet(pBlock->pDataBlock, slotId);
186✔
7027
  if (NULL == pCol) {
186!
7028
    taosMemoryFree(res);
×
7029
    return TSDB_CODE_OUT_OF_RANGE;
×
7030
  }
7031

7032
  int32_t code = colDataSetVal(pCol, pBlock->info.rows, res, false);
186✔
7033

7034
  taosMemoryFree(res);
186!
7035
  return code;
186✔
7036
}
7037

7038
int32_t irateFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
27,285✔
7039
  int32_t          slotId = pCtx->pExpr->base.resSchema.slotId;
27,285✔
7040
  SColumnInfoData* pCol = taosArrayGet(pBlock->pDataBlock, slotId);
27,285✔
7041
  if (NULL == pCol) {
27,285!
7042
    return TSDB_CODE_OUT_OF_RANGE;
×
7043
  }
7044

7045
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
27,285✔
7046
  pResInfo->isNullRes = (pResInfo->numOfRes == 0) ? 1 : 0;
27,285✔
7047

7048
  SRateInfo* pInfo = GET_ROWCELL_INTERBUF(pResInfo);
27,285✔
7049
  double     result = doCalcRate(pInfo, (double)TSDB_TICK_PER_SECOND(pCtx->param[1].param.i));
27,285!
7050
  int32_t    code = colDataSetVal(pCol, pBlock->info.rows, (const char*)&result, pResInfo->isNullRes);
27,285✔
7051

7052
  return code;
27,285✔
7053
}
7054

7055
int32_t groupConstValueFunction(SqlFunctionCtx* pCtx) {
83,558,562✔
7056
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
83,558,562✔
7057
  SGroupKeyInfo*       pInfo = GET_ROWCELL_INTERBUF(pResInfo);
83,558,562✔
7058

7059
  SInputColumnInfoData* pInput = &pCtx->input;
83,558,562✔
7060
  SColumnInfoData*      pInputCol = pInput->pData[0];
83,558,562✔
7061

7062
  int32_t startIndex = pInput->startRowIndex;
83,558,562✔
7063

7064
  // escape rest of data blocks to avoid first entry to be overwritten.
7065
  if (pInfo->hasResult) {
83,558,562✔
7066
    goto _group_value_over;
10,440,967✔
7067
  }
7068

7069
  if (pInputCol->pData == NULL || colDataIsNull_s(pInputCol, startIndex)) {
145,991,883✔
7070
    pInfo->isNull = true;
1,591,611✔
7071
    pInfo->hasResult = true;
1,591,611✔
7072
    goto _group_value_over;
1,591,611✔
7073
  }
7074

7075
  char* data = colDataGetData(pInputCol, startIndex);
71,525,984!
7076
  if (IS_VAR_DATA_TYPE(pInputCol->info.type)) {
71,525,984!
7077
    (void)memcpy(pInfo->data, data,
50,587,655✔
7078
                 (pInputCol->info.type == TSDB_DATA_TYPE_JSON) ? getJsonValueLen(data) : varDataTLen(data));
50,587,655✔
7079
  } else {
7080
    (void)memcpy(pInfo->data, data, pInputCol->info.bytes);
20,938,329✔
7081
  }
7082
  pInfo->hasResult = true;
71,525,984✔
7083

7084
_group_value_over:
83,558,562✔
7085

7086
  SET_VAL(pResInfo, 1, 1);
83,558,562✔
7087
  return TSDB_CODE_SUCCESS;
83,558,562✔
7088
}
7089

7090
int32_t groupKeyFunction(SqlFunctionCtx* pCtx) { return groupConstValueFunction(pCtx); }
83,572,896✔
7091

7092
int32_t groupConstValueFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
72,013,346✔
7093
  int32_t          slotId = pCtx->pExpr->base.resSchema.slotId;
72,013,346✔
7094
  int32_t          code = TSDB_CODE_SUCCESS;
72,013,346✔
7095
  SColumnInfoData* pCol = taosArrayGet(pBlock->pDataBlock, slotId);
72,013,346✔
7096
  if (NULL == pCol) {
72,024,058!
7097
    return TSDB_CODE_OUT_OF_RANGE;
×
7098
  }
7099

7100
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
72,024,058✔
7101

7102
  SGroupKeyInfo* pInfo = GET_ROWCELL_INTERBUF(pResInfo);
72,024,058✔
7103

7104
  if (pInfo->hasResult) {
72,024,058!
7105
    int32_t currentRow = pBlock->info.rows;
72,060,305✔
7106
    for (; currentRow < pBlock->info.rows + pResInfo->numOfRes; ++currentRow) {
144,664,444✔
7107
      code = colDataSetVal(pCol, currentRow, pInfo->data, pInfo->isNull ? true : false);
72,043,310✔
7108
      if (TSDB_CODE_SUCCESS != code) {
72,604,139!
7109
        return code;
×
7110
      }
7111
    }
7112
  } else {
7113
    pResInfo->numOfRes = 0;
×
7114
  }
7115

7116
  return code;
72,584,887✔
7117
}
7118

7119
int32_t groupKeyFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) { return groupConstValueFinalize(pCtx, pBlock); }
72,002,326✔
7120

7121
int32_t groupKeyCombine(SqlFunctionCtx* pDestCtx, SqlFunctionCtx* pSourceCtx) {
×
7122
  SResultRowEntryInfo* pDResInfo = GET_RES_INFO(pDestCtx);
×
7123
  SGroupKeyInfo*       pDBuf = GET_ROWCELL_INTERBUF(pDResInfo);
×
7124

7125
  SResultRowEntryInfo* pSResInfo = GET_RES_INFO(pSourceCtx);
×
7126
  SGroupKeyInfo*       pSBuf = GET_ROWCELL_INTERBUF(pSResInfo);
×
7127

7128
  // escape rest of data blocks to avoid first entry to be overwritten.
7129
  if (pDBuf->hasResult) {
×
7130
    goto _group_key_over;
×
7131
  }
7132

7133
  if (pSBuf->isNull) {
×
7134
    pDBuf->isNull = true;
×
7135
    pDBuf->hasResult = true;
×
7136
    goto _group_key_over;
×
7137
  }
7138

7139
  if (IS_VAR_DATA_TYPE(pSourceCtx->resDataInfo.type)) {
×
7140
    (void)memcpy(pDBuf->data, pSBuf->data,
×
7141
                 (pSourceCtx->resDataInfo.type == TSDB_DATA_TYPE_JSON) ? getJsonValueLen(pSBuf->data)
×
7142
                                                                       : varDataTLen(pSBuf->data));
×
7143
  } else {
7144
    (void)memcpy(pDBuf->data, pSBuf->data, pSourceCtx->resDataInfo.bytes);
×
7145
  }
7146

7147
  pDBuf->hasResult = true;
×
7148

7149
_group_key_over:
×
7150

7151
  SET_VAL(pDResInfo, 1, 1);
×
7152
  return TSDB_CODE_SUCCESS;
×
7153
}
7154

7155
int32_t cachedLastRowFunction(SqlFunctionCtx* pCtx) {
2,406✔
7156
  int32_t numOfElems = 0;
2,406✔
7157

7158
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
2,406✔
7159
  SFirstLastRes*       pInfo = GET_ROWCELL_INTERBUF(pResInfo);
2,406✔
7160

7161
  SInputColumnInfoData* pInput = &pCtx->input;
2,406✔
7162
  SColumnInfoData*      pInputCol = pInput->pData[0];
2,406✔
7163

7164
  int32_t bytes = pInputCol->info.bytes;
2,406✔
7165
  pInfo->bytes = bytes;
2,406✔
7166

7167
  SColumnInfoData* pkCol = pInput->pPrimaryKey;
2,406✔
7168
  pInfo->pkType = -1;
2,406✔
7169
  __compar_fn_t pkCompareFn = NULL;
2,406✔
7170
  if (pCtx->hasPrimaryKey) {
2,406✔
7171
    pInfo->pkType = pkCol->info.type;
20✔
7172
    pInfo->pkBytes = pkCol->info.bytes;
20✔
7173
    pkCompareFn = getKeyComparFunc(pInfo->pkType, TSDB_ORDER_DESC);
20✔
7174
  }
7175

7176
  // TODO it traverse the different way.
7177
  // last_row function does not ignore the null value
7178
  for (int32_t i = pInput->numOfRows + pInput->startRowIndex - 1; i >= pInput->startRowIndex; --i) {
4,822✔
7179
    numOfElems++;
2,416✔
7180

7181
    bool  isNull = colDataIsNull(pInputCol, pInput->numOfRows, i, NULL);
2,416✔
7182
    char* data = isNull ? NULL : colDataGetData(pInputCol, i);
2,416!
7183

7184
    TSKEY cts = getRowPTs(pInput->pPTS, i);
2,416!
7185
    if (pResInfo->numOfRes == 0 || pInfo->ts < cts) {
2,416✔
7186
      int32_t code = doSaveLastrow(pCtx, data, i, cts, pInfo);
2,088✔
7187
      if (code != TSDB_CODE_SUCCESS) {
2,088!
7188
        return code;
×
7189
      }
7190
      pResInfo->numOfRes = 1;
2,088✔
7191
    }
7192
  }
7193

7194
  SET_VAL(pResInfo, numOfElems, 1);
2,406!
7195
  return TSDB_CODE_SUCCESS;
2,406✔
7196
}
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