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

taosdata / TDengine / #3559

18 Dec 2024 12:59AM UTC coverage: 59.805% (+0.03%) from 59.778%
#3559

push

travis-ci

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

merge: main to 3.0 branch

132705 of 287544 branches covered (46.15%)

Branch coverage included in aggregate %.

87 of 95 new or added lines in 19 files covered. (91.58%)

1132 existing lines in 133 files now uncovered.

209591 of 284807 relevant lines covered (73.59%)

8125235.78 hits per line

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

71.62
/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; }
20,810,330✔
32
bool ignoreNull(int8_t ignoreOption) { return (ignoreOption & 0x2) == 0x2; }
224,586✔
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,500✔
194
  SFuncInputRowIter* pIter = &pCtx->rowIter;
295,500✔
195

196
  if (!pCtx->bInputFinished) {
295,500!
197
    pIter->pInput = &pCtx->input;
295,504✔
198
    pIter->tsList = (TSKEY*)pIter->pInput->pPTS->pData;
295,504✔
199
    pIter->pDataCol = pIter->pInput->pData[0];
295,504✔
200
    pIter->pPkCol = pIter->pInput->pPrimaryKey;
295,504✔
201
    pIter->rowIndex = pIter->pInput->startRowIndex;
295,504✔
202
    pIter->inputEndIndex = pIter->rowIndex + pIter->pInput->numOfRows - 1;
295,504✔
203
    pIter->pSrcBlock = pCtx->pSrcBlock;
295,504✔
204
    if (!pIter->hasGroupId || pIter->groupId != pIter->pSrcBlock->info.id.groupId) {
295,504✔
205
      pIter->hasGroupId = true;
43,059✔
206
      pIter->groupId = pIter->pSrcBlock->info.id.groupId;
43,059✔
207
      pIter->hasPrev = false;
43,059✔
208
    }
209
  } else {
210
    pIter->finalRow = true;
×
211
  }
212
}
295,500✔
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) {
18,119,263✔
337
  pRow->ts = pIter->tsList[rowIndex];
18,119,263✔
338
  pRow->ts = pIter->tsList[rowIndex];
18,119,263✔
339
  pRow->isDataNull = colDataIsNull_f(pIter->pDataCol->nullbitmap, rowIndex);
18,119,263✔
340
  pRow->pData = colDataGetData(pIter->pDataCol, rowIndex);
18,119,263!
341
  pRow->pPk = setPk ? colDataGetData(pIter->pPkCol, rowIndex) : NULL;
18,119,263!
342
  pRow->block = pIter->pSrcBlock;
18,119,263✔
343
  pRow->rowIndex = rowIndex;
18,119,263✔
344
}
18,119,263✔
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) {
18,427,189✔
383
  if (pIter->rowIndex <= pIter->inputEndIndex) {
18,427,189✔
384
    setInputRowInfo(pRow, pIter, pIter->rowIndex, false);
18,119,049✔
385
    ++pIter->rowIndex;
18,120,305✔
386
    return true;
18,120,305✔
387
  } else {
388
    return false;
308,140✔
389
  }
390
}
391

392
int32_t funcInputGetNextRow(SqlFunctionCtx* pCtx, SFuncInputRow* pRow, bool* res) {
18,428,203✔
393
  SFuncInputRowIter* pIter = &pCtx->rowIter;
18,428,203✔
394
  if (pCtx->hasPrimaryKey) {
18,428,203✔
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);
18,427,873✔
403
    return TSDB_CODE_SUCCESS;
18,428,562✔
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) {
16,702,929✔
411
  if (pCtx->subsidiaries.num <= 0) {
16,702,929!
412
    return TSDB_CODE_SUCCESS;
×
413
  }
414

415
  for (int32_t j = 0; j < pCtx->subsidiaries.num; ++j) {
48,824,998✔
416
    SqlFunctionCtx* pc = pCtx->subsidiaries.pCtx[j];
32,122,069✔
417

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

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

427
    char* pData = colDataGetData(pSrcCol, rowIndex);
32,122,069!
428

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

432
    SColumnInfoData* pDstCol = taosArrayGet(pCtx->pDstBlock->pDataBlock, dstSlotId);
32,122,069✔
433
    if (NULL == pDstCol) {
32,122,069!
434
      return TSDB_CODE_OUT_OF_RANGE;
×
435
    }
436
    if (colDataIsNull_s(pSrcCol, rowIndex) == true) {
64,244,138✔
437
      colDataSetNULL(pDstCol, pos);
1,548,060✔
438
    } else {
439
      int32_t code = colDataSetVal(pDstCol, pos, pData, false);
30,574,009✔
440
      if (TSDB_CODE_SUCCESS != code) {
30,574,009!
441
        return code;
×
442
      }
443
    }
444
  }
445
  return TSDB_CODE_SUCCESS;
16,702,929✔
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) {
278,142,485✔
454
  if (pResultInfo->initialized) {
278,142,485✔
455
    return TSDB_CODE_SUCCESS;  // already initialized
12,427✔
456
  }
457

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

462
  initResultRowEntry(pResultInfo, pCtx->resDataInfo.interBufSize);
278,130,058✔
463
  return TSDB_CODE_SUCCESS;
278,130,058✔
464
}
465

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

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

479
  return code;
121,777,422✔
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) {
143,288✔
513
  SNode* pParam = nodesListGetNode(pFunc->pParameterList, 0);
143,288✔
514
  if (QUERY_NODE_COLUMN == nodeType(pParam) && PRIMARYKEY_TIMESTAMP_COL_ID == ((SColumnNode*)pParam)->colId) {
143,298✔
515
    return FUNC_DATA_REQUIRED_NOT_LOAD;
77,349✔
516
  }
517
  return FUNC_DATA_REQUIRED_SMA_LOAD;
65,949✔
518
}
519

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

525
static int64_t getNumOfElems(SqlFunctionCtx* pCtx) {
96,710,203✔
526
  int64_t numOfElem = 0;
96,710,203✔
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;
96,710,203✔
534
  SColumnInfoData*      pInputCol = pInput->pData[0];
96,710,203✔
535
  if (1 == pInput->numOfRows && pInput->blankFill) {
96,710,203✔
536
    return 0;
410,585✔
537
  }
538
  if (pInput->colDataSMAIsSet && pInput->totalRows == pInput->numOfRows) {
96,299,618!
539
    numOfElem = pInput->numOfRows - pInput->pColumnDataAgg[0]->numOfNull;
2,884✔
540
  } else {
541
    if (pInputCol->hasNull) {
96,296,734✔
542
      for (int32_t i = pInput->startRowIndex; i < pInput->startRowIndex + pInput->numOfRows; ++i) {
203,447,808✔
543
        if (colDataIsNull(pInputCol, pInput->totalRows, i, NULL)) {
356,607,172!
544
          continue;
1,975,082✔
545
        }
546
        numOfElem += 1;
176,328,504✔
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;
71,152,512✔
552
    }
553
  }
554
  return numOfElem;
96,299,618✔
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) {
96,731,547✔
562
  int64_t numOfElem = 0;
96,731,547✔
563

564
  SResultRowEntryInfo*  pResInfo = GET_RES_INFO(pCtx);
96,731,547✔
565
  SInputColumnInfoData* pInput = &pCtx->input;
96,731,547✔
566

567
  int32_t type = pInput->pData[0]->info.type;
96,731,547✔
568

569
  char* buf = GET_ROWCELL_INTERBUF(pResInfo);
96,731,547✔
570
  if (IS_NULL_TYPE(type)) {
96,731,547✔
571
    // select count(NULL) returns 0
572
    numOfElem = 1;
11,808✔
573
    *((int64_t*)buf) += 0;
11,808✔
574
  } else {
575
    numOfElem = getNumOfElems(pCtx);
96,719,739✔
576
    *((int64_t*)buf) += numOfElem;
96,358,969✔
577
  }
578

579
  if (tsCountAlwaysReturnValue) {
96,370,777!
580
    pResInfo->numOfRes = 1;
96,450,859✔
581
  } else {
582
    SET_VAL(pResInfo, *((int64_t*)buf), 1);
×
583
  }
584

585
  return TSDB_CODE_SUCCESS;
96,370,777✔
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,981,007✔
614
  int32_t numOfElem = 0;
73,981,007✔
615

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

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

624
  if (IS_NULL_TYPE(type)) {
73,981,007✔
625
    numOfElem = 0;
215✔
626
    goto _sum_over;
215✔
627
  }
628

629
  if (pInput->colDataSMAIsSet) {
73,980,792✔
630
    numOfElem = pInput->numOfRows - pAgg->numOfNull;
86✔
631

632
    if (IS_SIGNED_NUMERIC_TYPE(type)) {
86!
633
      pSumRes->isum += pAgg->sum;
86✔
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,980,706✔
641

642
    int32_t start = pInput->startRowIndex;
73,980,706✔
643
    int32_t numOfRows = pInput->numOfRows;
73,980,706✔
644

645
    if (IS_SIGNED_NUMERIC_TYPE(type) || type == TSDB_DATA_TYPE_BOOL) {
73,980,706!
646
      if (type == TSDB_DATA_TYPE_TINYINT || type == TSDB_DATA_TYPE_BOOL) {
73,135,169!
647
        LIST_ADD_N(pSumRes->isum, pCol, start, numOfRows, int8_t, numOfElem);
1,322,022✔
648
      } else if (type == TSDB_DATA_TYPE_SMALLINT) {
72,767,782✔
649
        LIST_ADD_N(pSumRes->isum, pCol, start, numOfRows, int16_t, numOfElem);
469,695✔
650
      } else if (type == TSDB_DATA_TYPE_INT) {
72,718,043✔
651
        LIST_ADD_N(pSumRes->isum, pCol, start, numOfRows, int32_t, numOfElem);
271,847,070✔
652
      } else if (type == TSDB_DATA_TYPE_BIGINT) {
17,483,579✔
653
        LIST_ADD_N(pSumRes->isum, pCol, start, numOfRows, int64_t, numOfElem);
67,969,158✔
654
      }
655
    } else if (IS_UNSIGNED_NUMERIC_TYPE(type)) {
845,537!
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) {
845,455✔
666
      LIST_ADD_N(pSumRes->dsum, pCol, start, numOfRows, double, numOfElem);
2,124,756✔
667
    } else if (type == TSDB_DATA_TYPE_FLOAT) {
762,774✔
668
      LIST_ADD_N(pSumRes->dsum, pCol, start, numOfRows, float, numOfElem);
1,709,408✔
669
    }
670
  }
671

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

677
_sum_over:
74,223,515✔
678
  if (numOfElem == 0) {
73,981,007✔
679
    if (tsCountAlwaysReturnValue && pCtx->pExpr->pExpr->_function.pFunctNode->hasOriginalFunc &&
98,168✔
680
        fmIsCountLikeFunc(pCtx->pExpr->pExpr->_function.pFunctNode->originalFuncId)) {
11,384✔
681
      numOfElem = 1;
46✔
682
    }
683
  }
684
  // data in the check operation are all null, not output
685
  SET_VAL(GET_RES_INFO(pCtx), numOfElem, 1);
73,981,007✔
686
  return TSDB_CODE_SUCCESS;
73,981,007✔
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) {
45✔
750
  SResultRowEntryInfo* pDResInfo = GET_RES_INFO(pDestCtx);
45✔
751
  SSumRes*             pDBuf = GET_ROWCELL_INTERBUF(pDResInfo);
45✔
752

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

757
  if (IS_SIGNED_NUMERIC_TYPE(type) || type == TSDB_DATA_TYPE_BOOL) {
45!
758
    pDBuf->isum += pSBuf->isum;
45✔
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);
45✔
765
  pDResInfo->isNullRes &= pSResInfo->isNullRes;
45✔
766
  return TSDB_CODE_SUCCESS;
45✔
767
}
768

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

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

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

786
  SMinmaxResInfo* buf = GET_ROWCELL_INTERBUF(pResultInfo);
36,229,428✔
787
  buf->assign = false;
36,229,428✔
788
  buf->tuplePos.pageId = -1;
36,229,428✔
789

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

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

801
int32_t minFunction(SqlFunctionCtx* pCtx) {
19,924,476✔
802
  int32_t numOfElems = 0;
19,924,476✔
803
  int32_t code = doMinMaxHelper(pCtx, 1, &numOfElems);
19,924,476✔
804
  if (code != TSDB_CODE_SUCCESS) {
20,060,917!
805
    return code;
×
806
  }
807
  SET_VAL(GET_RES_INFO(pCtx), numOfElems, 1);
20,060,917✔
808
  return TSDB_CODE_SUCCESS;
20,060,917✔
809
}
810

811
int32_t maxFunction(SqlFunctionCtx* pCtx) {
20,019,375✔
812
  int32_t numOfElems = 0;
20,019,375✔
813
  int32_t code = doMinMaxHelper(pCtx, 0, &numOfElems);
20,019,375✔
814
  if (code != TSDB_CODE_SUCCESS) {
20,108,519!
815
    return code;
×
816
  }
817
  SET_VAL(GET_RES_INFO(pCtx), numOfElems, 1);
20,108,519✔
818
  return TSDB_CODE_SUCCESS;
20,108,519✔
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) {
34,894,952✔
826
  int32_t code = TSDB_CODE_SUCCESS;
34,894,952✔
827

828
  SResultRowEntryInfo* pEntryInfo = GET_RES_INFO(pCtx);
34,894,952✔
829
  SMinmaxResInfo*      pRes = GET_ROWCELL_INTERBUF(pEntryInfo);
34,894,952✔
830

831
  int32_t slotId = pCtx->pExpr->base.resSchema.slotId;
34,894,952✔
832
  int32_t currentRow = pBlock->info.rows;
34,894,952✔
833

834
  SColumnInfoData* pCol = taosArrayGet(pBlock->pDataBlock, slotId);
34,894,952✔
835
  if (NULL == pCol) {
34,899,698!
836
    return TSDB_CODE_OUT_OF_RANGE;
×
837
  }
838
  pEntryInfo->isNullRes = (pEntryInfo->numOfRes == 0) ? 1 : 0;
34,899,698✔
839

840
  // NOTE: do nothing change it, for performance issue
841
  if (!pEntryInfo->isNullRes) {
34,899,698✔
842
    switch (pCol->info.type) {
28,628,961!
843
      case TSDB_DATA_TYPE_UBIGINT:
10,736,324✔
844
      case TSDB_DATA_TYPE_BIGINT:
845
        ((int64_t*)pCol->pData)[currentRow] = pRes->v;
10,736,324✔
846
        break;
10,736,324✔
847
      case TSDB_DATA_TYPE_UINT:
17,322,928✔
848
      case TSDB_DATA_TYPE_INT:
849
        colDataSetInt32(pCol, currentRow, (int32_t*)&pRes->v);
17,322,928✔
850
        break;
17,322,928✔
851
      case TSDB_DATA_TYPE_USMALLINT:
198,171✔
852
      case TSDB_DATA_TYPE_SMALLINT:
853
        colDataSetInt16(pCol, currentRow, (int16_t*)&pRes->v);
198,171✔
854
        break;
198,171✔
855
      case TSDB_DATA_TYPE_BOOL:
186,048✔
856
      case TSDB_DATA_TYPE_UTINYINT:
857
      case TSDB_DATA_TYPE_TINYINT:
858
        colDataSetInt8(pCol, currentRow, (int8_t*)&pRes->v);
186,048✔
859
        break;
186,048✔
860
      case TSDB_DATA_TYPE_DOUBLE:
211,545✔
861
        colDataSetDouble(pCol, currentRow, (double*)&pRes->v);
211,545✔
862
        break;
211,545✔
863
      case TSDB_DATA_TYPE_FLOAT: {
2,519✔
864
        float v = GET_FLOAT_VAL(&pRes->v);
2,519✔
865
        colDataSetFloat(pCol, currentRow, &v);
2,519✔
866
        break;
2,519✔
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);
6,270,737!
880
  }
881

882
  taosMemoryFreeClear(pRes->str);
34,899,698!
883
  if (pCtx->subsidiaries.num > 0) {
34,899,698✔
884
    if (pEntryInfo->numOfRes > 0) {
81,788✔
885
      code = setSelectivityValue(pCtx, pBlock, &pRes->tuplePos, currentRow);
79,380✔
886
    } else {
887
      code = setSelectivityValue(pCtx, pBlock, &pRes->nullTuplePos, currentRow);
2,408✔
888
    }
889
  }
890

891
  return code;
34,905,181✔
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) {
34,660,184✔
913
  if (pCtx->subsidiaries.num <= 0) {
34,660,184✔
914
    return TSDB_CODE_SUCCESS;
34,519,520✔
915
  }
916

917
  if ((pCtx->saveHandle.pBuf != NULL && pTuplePos->pageId != -1) ||
140,664!
918
      (pCtx->saveHandle.pState && pTuplePos->streamTupleKey.ts > 0)) {
61,801!
919
    int32_t numOfCols = pCtx->subsidiaries.num;
140,669✔
920
    char*   p = NULL;
140,669✔
921
    int32_t code = loadTupleData(pCtx, pTuplePos, &p);
140,669✔
922
    if (p == NULL || TSDB_CODE_SUCCESS != code) {
145,085!
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;
145,085✔
929
    char* pStart = (char*)(nullList + numOfCols * sizeof(bool));
145,085✔
930

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

936
      // group_key function has its own process function
937
      // do not process there
938
      if (fmIsGroupKeyFunc(pc->functionId)) {
174,773✔
939
        continue;
25,703✔
940
      }
941

942
      SColumnInfoData* pDstCol = taosArrayGet(pBlock->pDataBlock, dstSlotId);
149,072✔
943
      if (NULL == pDstCol) {
149,068!
944
        return TSDB_CODE_OUT_OF_RANGE;
×
945
      }
946
      if (nullList[j]) {
149,068✔
947
        colDataSetNULL(pDstCol, rowIndex);
212!
948
      } else {
949
        code = colDataSetVal(pDstCol, rowIndex, pStart, false);
148,856✔
950
        if (TSDB_CODE_SUCCESS != code) {
148,867!
951
          return code;
×
952
        }
953
      }
954
      pStart += pDstCol->info.bytes;
149,079✔
955
    }
956
  }
957

958
  return TSDB_CODE_SUCCESS;
145,089✔
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) {
57✔
1007
  SResultRowEntryInfo* pDResInfo = GET_RES_INFO(pDestCtx);
57✔
1008
  SMinmaxResInfo*      pDBuf = GET_ROWCELL_INTERBUF(pDResInfo);
57✔
1009

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

1014
  switch (type) {
57!
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:
54✔
1025
    case TSDB_DATA_TYPE_INT:
1026
      if (pSBuf->assign && (COMPARE_MINMAX_DATA(int32_t) || !pDBuf->assign)) {
54!
1027
        pDBuf->v = pSBuf->v;
31✔
1028
        replaceTupleData(&pDBuf->tuplePos, &pSBuf->tuplePos);
31✔
1029
        pDBuf->assign = true;
31✔
1030
      }
1031
      break;
54✔
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);
57✔
1066
  pDResInfo->isNullRes &= pSResInfo->isNullRes;
57✔
1067
  return TSDB_CODE_SUCCESS;
57✔
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) {
46✔
1074
  return minMaxCombine(pDestCtx, pSourceCtx, 0);
46✔
1075
}
1076

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

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

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

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

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

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

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

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

1110
  int32_t start = pInput->startRowIndex;
319,280✔
1111
  int32_t numOfRows = pInput->numOfRows;
319,280✔
1112

1113
  if (IS_NULL_TYPE(type)) {
319,280✔
1114
    numOfElem = 0;
149✔
1115
    goto _stddev_over;
149✔
1116
  }
1117

1118
  switch (type) {
319,131!
1119
    case TSDB_DATA_TYPE_TINYINT: {
15,783✔
1120
      int8_t* plist = (int8_t*)pCol->pData;
15,783✔
1121
      for (int32_t i = start; i < numOfRows + start; ++i) {
92,784✔
1122
        if (pCol->hasNull && colDataIsNull_f(pCol->nullbitmap, i)) {
77,001✔
1123
          continue;
36,199✔
1124
        }
1125

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

1132
      break;
15,783✔
1133
    }
1134

1135
    case TSDB_DATA_TYPE_SMALLINT: {
201,801✔
1136
      int16_t* plist = (int16_t*)pCol->pData;
201,801✔
1137
      for (int32_t i = start; i < numOfRows + pInput->startRowIndex; ++i) {
866,650✔
1138
        if (pCol->hasNull && colDataIsNull_f(pCol->nullbitmap, i)) {
664,849✔
1139
          continue;
186,410✔
1140
        }
1141

1142
        numOfElem += 1;
478,439✔
1143
        pStdRes->count += 1;
478,439✔
1144
        pStdRes->isum += plist[i];
478,439✔
1145
        pStdRes->quadraticISum += plist[i] * plist[i];
478,439✔
1146
      }
1147
      break;
201,801✔
1148
    }
1149

1150
    case TSDB_DATA_TYPE_INT: {
16,718✔
1151
      int32_t* plist = (int32_t*)pCol->pData;
16,718✔
1152
      for (int32_t i = start; i < numOfRows + pInput->startRowIndex; ++i) {
161,945✔
1153
        if (pCol->hasNull && colDataIsNull_f(pCol->nullbitmap, i)) {
145,227✔
1154
          continue;
26,207✔
1155
        }
1156

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

1163
      break;
16,718✔
1164
    }
1165

1166
    case TSDB_DATA_TYPE_BIGINT: {
20,825✔
1167
      int64_t* plist = (int64_t*)pCol->pData;
20,825✔
1168
      for (int32_t i = start; i < numOfRows + pInput->startRowIndex; ++i) {
733,450✔
1169
        if (pCol->hasNull && colDataIsNull_f(pCol->nullbitmap, i)) {
712,625✔
1170
          continue;
95,465✔
1171
        }
1172

1173
        numOfElem += 1;
617,160✔
1174
        pStdRes->count += 1;
617,160✔
1175
        pStdRes->isum += plist[i];
617,160✔
1176
        pStdRes->quadraticISum += plist[i] * plist[i];
617,160✔
1177
      }
1178
      break;
20,825✔
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: {
13,855✔
1244
      float* plist = (float*)pCol->pData;
13,855✔
1245
      for (int32_t i = start; i < numOfRows + pInput->startRowIndex; ++i) {
648,127✔
1246
        if (pCol->hasNull && colDataIsNull_f(pCol->nullbitmap, i)) {
634,272✔
1247
          continue;
100,160✔
1248
        }
1249

1250
        numOfElem += 1;
534,112✔
1251
        pStdRes->count += 1;
534,112✔
1252
        pStdRes->dsum += plist[i];
534,112✔
1253
        pStdRes->quadraticDSum += plist[i] * plist[i];
534,112✔
1254
      }
1255
      break;
13,855✔
1256
    }
1257

1258
    case TSDB_DATA_TYPE_DOUBLE: {
50,147✔
1259
      double* plist = (double*)pCol->pData;
50,147✔
1260
      for (int32_t i = start; i < numOfRows + pInput->startRowIndex; ++i) {
1,956,090✔
1261
        if (pCol->hasNull && colDataIsNull_f(pCol->nullbitmap, i)) {
1,905,943✔
1262
          continue;
598,796✔
1263
        }
1264

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

1273
    default:
×
1274
      break;
×
1275
  }
1276

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

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

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

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

1306
  if (IS_NULL_TYPE(pCol->info.type)) {
9,082!
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,082!
1312
    return TSDB_CODE_FUNC_FUNTION_PARA_TYPE;
×
1313
  }
1314

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

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

1324
  SET_VAL(GET_RES_INFO(pCtx), 1, 1);
9,082✔
1325
  return TSDB_CODE_SUCCESS;
9,082✔
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) {
273,429✔
1396
  SInputColumnInfoData* pInput = &pCtx->input;
273,429✔
1397
  SStdRes*              pStddevRes = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
273,429✔
1398
  int32_t               type = pStddevRes->type;
273,429✔
1399
  double                avg;
1400

1401
  if (pStddevRes->count == 0) {
273,429✔
1402
    GET_RES_INFO(pCtx)->numOfRes = 0;
56,952✔
1403
    return functionFinalize(pCtx, pBlock);
56,952✔
1404
  }
1405

1406
  if (IS_SIGNED_NUMERIC_TYPE(type)) {
216,477!
1407
    avg = pStddevRes->isum / ((double)pStddevRes->count);
182,199✔
1408
    pStddevRes->result = sqrt(fabs(pStddevRes->quadraticISum / ((double)pStddevRes->count) - avg * avg));
182,199✔
1409
  } else if (IS_UNSIGNED_NUMERIC_TYPE(type)) {
34,278!
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);
34,276✔
1414
    pStddevRes->result = sqrt(fabs(pStddevRes->quadraticDSum / ((double)pStddevRes->count) - avg * avg));
34,276✔
1415
  }
1416

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

1422
  return functionFinalize(pCtx, pBlock);
216,477✔
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,075✔
1456
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
9,075✔
1457
  SStdRes*             pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
9,075✔
1458
  int32_t              resultBytes = getStdInfoSize();
9,075✔
1459
  char*                res = taosMemoryCalloc(resultBytes + VARSTR_HEADER_SIZE, sizeof(char));
9,075!
1460

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

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

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

1476
  taosMemoryFree(res);
9,075!
1477
  return code;
9,075✔
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,084✔
1496
  pEnv->calcMemSize = sizeof(SLeastSQRInfo);
8,084✔
1497
  return true;
8,084✔
1498
}
1499

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

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

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

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

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

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

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

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

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

1531
  switch (type) {
48,858!
1532
    case TSDB_DATA_TYPE_TINYINT: {
4,676✔
1533
      int8_t* plist = (int8_t*)pCol->pData;
4,676✔
1534
      for (int32_t i = start; i < numOfRows + pInput->startRowIndex; ++i) {
9,928✔
1535
        if (pCol->hasNull && colDataIsNull_f(pCol->nullbitmap, i)) {
5,252✔
1536
          continue;
3,036✔
1537
        }
1538
        numOfElem++;
2,216✔
1539
        LEASTSQR_CAL(param, x, plist, i, pInfo->stepVal);
2,216✔
1540
      }
1541
      break;
4,676✔
1542
    }
1543
    case TSDB_DATA_TYPE_SMALLINT: {
9,324✔
1544
      int16_t* plist = (int16_t*)pCol->pData;
9,324✔
1545
      for (int32_t i = start; i < numOfRows + pInput->startRowIndex; ++i) {
433,129✔
1546
        if (pCol->hasNull && colDataIsNull_f(pCol->nullbitmap, i)) {
423,805✔
1547
          continue;
285,077✔
1548
        }
1549

1550
        numOfElem++;
138,728✔
1551
        LEASTSQR_CAL(param, x, plist, i, pInfo->stepVal);
138,728✔
1552
      }
1553
      break;
9,324✔
1554
    }
1555

1556
    case TSDB_DATA_TYPE_INT: {
10,050✔
1557
      int32_t* plist = (int32_t*)pCol->pData;
10,050✔
1558
      for (int32_t i = start; i < numOfRows + pInput->startRowIndex; ++i) {
173,800✔
1559
        if (pCol->hasNull && colDataIsNull_f(pCol->nullbitmap, i)) {
163,750✔
1560
          continue;
3,284✔
1561
        }
1562

1563
        numOfElem++;
160,466✔
1564
        LEASTSQR_CAL(param, x, plist, i, pInfo->stepVal);
160,466✔
1565
      }
1566
      break;
10,050✔
1567
    }
1568

1569
    case TSDB_DATA_TYPE_BIGINT: {
5,190✔
1570
      int64_t* plist = (int64_t*)pCol->pData;
5,190✔
1571
      for (int32_t i = start; i < numOfRows + pInput->startRowIndex; ++i) {
146,642✔
1572
        if (pCol->hasNull && colDataIsNull_f(pCol->nullbitmap, i)) {
141,452✔
1573
          continue;
138,836✔
1574
        }
1575

1576
        numOfElem++;
2,616✔
1577
        LEASTSQR_CAL(param, x, plist, i, pInfo->stepVal);
2,616✔
1578
      }
1579
      break;
5,190✔
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: {
9,322✔
1633
      float* plist = (float*)pCol->pData;
9,322✔
1634
      for (int32_t i = start; i < numOfRows + pInput->startRowIndex; ++i) {
163,228✔
1635
        if (pCol->hasNull && colDataIsNull_f(pCol->nullbitmap, i)) {
153,906✔
1636
          continue;
149,690✔
1637
        }
1638

1639
        numOfElem++;
4,216✔
1640
        LEASTSQR_CAL(param, x, plist, i, pInfo->stepVal);
4,216✔
1641
      }
1642
      break;
9,322✔
1643
    }
1644

1645
    case TSDB_DATA_TYPE_DOUBLE: {
9,989✔
1646
      double* plist = (double*)pCol->pData;
9,989✔
1647
      for (int32_t i = start; i < numOfRows + pInput->startRowIndex; ++i) {
302,018✔
1648
        if (pCol->hasNull && colDataIsNull_f(pCol->nullbitmap, i)) {
292,029✔
1649
          continue;
1,836✔
1650
        }
1651

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

UNCOV
1663
    default:
×
UNCOV
1664
      break;
×
1665
  }
1666

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

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

1672
  return TSDB_CODE_SUCCESS;
48,858✔
1673
}
1674

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

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

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

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

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

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

1699
  if (0 == param00) {
23,138✔
1700
    colDataSetNULL(pCol, currentRow);
18,676!
1701
    return TSDB_CODE_SUCCESS;
18,676✔
1702
  }
1703

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

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

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

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

1728
  return code;
4,466✔
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) {
5,168✔
1759
  if (pResultInfo->initialized) {
5,168!
1760
    return TSDB_CODE_SUCCESS;
×
1761
  }
1762
  if (TSDB_CODE_SUCCESS != functionSetup(pCtx, pResultInfo)) {
5,168!
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);
5,168✔
1768
  SET_DOUBLE_VAL(&pInfo->minval, DBL_MAX);
5,168✔
1769
  SET_DOUBLE_VAL(&pInfo->maxval, -DBL_MAX);
5,168✔
1770
  pInfo->numOfElems = 0;
5,168✔
1771

1772
  return TSDB_CODE_SUCCESS;
5,168✔
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) {
12,366✔
1787
  int32_t              code = TSDB_CODE_SUCCESS;
12,366✔
1788
  int32_t              numOfElems = 0;
12,366✔
1789
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
12,366✔
1790

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

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

1797
  SPercentileInfo* pInfo = GET_ROWCELL_INTERBUF(pResInfo);
12,366✔
1798
  if (pCtx->scanFlag == MAIN_SCAN && pInfo->stage == 0) {
12,366✔
1799
    pInfo->stage += 1;
5,168✔
1800

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

1814
  // the first stage, only acquire the min/max value
1815
  if (pInfo->stage == 0) {
10,590✔
1816
    if (pCtx->input.colDataSMAIsSet) {
6,198!
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;
6,198✔
1841
      for (int32_t i = start; i < pInput->numOfRows + start; ++i) {
317,836✔
1842
        if (colDataIsNull_f(pCol->nullbitmap, i)) {
311,638✔
1843
          continue;
2,400✔
1844
        }
1845

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

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

1854
        if (v > GET_DOUBLE_VAL(&pInfo->maxval)) {
309,238✔
1855
          SET_DOUBLE_VAL(&pInfo->maxval, v);
248,208✔
1856
        }
1857

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

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

1878
    SET_VAL(pResInfo, numOfElems, 1);
4,392!
1879
  }
1880

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

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

1889
  int32_t code = 0;
5,168✔
1890
  double  v = 0;
5,168✔
1891

1892
  tMemBucket** pMemBucket = &ppInfo->pMemBucket;
5,168✔
1893
  if ((*pMemBucket) != NULL && (*pMemBucket)->total > 0) {  // check for null
5,168!
1894
    if (pCtx->numOfParams > 2) {
3,392✔
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;
3,374✔
1935

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

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

1943
      tMemBucketDestroy(pMemBucket);
3,374✔
1944
      return functionFinalize(pCtx, pBlock);
3,374✔
1945
    }
1946
  } else {
1947
    return functionFinalize(pCtx, pBlock);
1,776✔
1948
  }
1949

1950
_fin_error:
×
1951

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

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

1964
int32_t getApercentileMaxSize() {
10,109✔
1965
  int32_t bytesHist =
10,109✔
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,109✔
1968
  return TMAX(bytesHist, bytesDigest);
10,109✔
1969
}
1970

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

1981
  return algoType;
22,312✔
1982
}
1983

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

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

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

2001
  SAPercentileInfo* pInfo = GET_ROWCELL_INTERBUF(pResultInfo);
291,710✔
2002

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

2007
  if (pCtx->numOfParams == 2) {
291,710✔
2008
    pInfo->algo = APERCT_ALGO_DEFAULT;
269,397✔
2009
  } else if (pCtx->numOfParams == 3) {
22,313!
2010
    pInfo->algo = getApercentileAlgo(varDataVal(pCtx->param[2].param.pz));
22,315✔
2011
    if (pInfo->algo == APERCT_ALGO_UNKNOWN) {
22,300!
2012
      return TSDB_CODE_FUNC_FUNTION_PARA_VALUE;
×
2013
    }
2014
  }
2015

2016
  char* tmp = (char*)pInfo + sizeof(SAPercentileInfo);
291,695✔
2017
  if (pInfo->algo == APERCT_ALGO_TDIGEST) {
291,695✔
2018
    pInfo->pTDigest = tdigestNewFrom(tmp, COMPRESSION);
11,156✔
2019
  } else {
2020
    buildHistogramInfo(pInfo);
280,539✔
2021
    pInfo->pHisto = tHistogramCreateFrom(tmp, MAX_HISTOGRAM_BIN);
280,545✔
2022
    qDebug("%s set up histogram, numOfElems:%" PRId64 ", numOfEntry:%d, pHisto:%p, elems:%p", __FUNCTION__,
280,542✔
2023
           pInfo->pHisto->numOfElems, pInfo->pHisto->numOfEntries, pInfo->pHisto, pInfo->pHisto->elems);
2024
  }
2025

2026
  return TSDB_CODE_SUCCESS;
291,708✔
2027
}
2028

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

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

2037
  SAPercentileInfo* pInfo = GET_ROWCELL_INTERBUF(pResInfo);
296,183✔
2038

2039
  int32_t start = pInput->startRowIndex;
296,183✔
2040
  if (pInfo->algo == APERCT_ALGO_TDIGEST) {
296,183✔
2041
    buildTDigestInfo(pInfo);
11,160✔
2042
    tdigestAutoFill(pInfo->pTDigest, COMPRESSION);
11,161✔
2043
    for (int32_t i = start; i < pInput->numOfRows + start; ++i) {
582,765✔
2044
      if (colDataIsNull_f(pCol->nullbitmap, i)) {
571,609✔
2045
        continue;
284,012✔
2046
      }
2047
      numOfElems += 1;
287,597✔
2048
      char* data = colDataGetData(pCol, i);
287,597!
2049

2050
      double  v = 0;  // value
287,597✔
2051
      int64_t w = 1;  // weigth
287,597✔
2052
      GET_TYPED_DATA(v, double, type, data);
287,597✔
2053
      int32_t code = tdigestAdd(pInfo->pTDigest, v, w);
287,597✔
2054
      if (code != TSDB_CODE_SUCCESS) {
287,592!
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);
285,023✔
2062
    qDebug("%s before add %d elements into histogram, total:%" PRId64 ", numOfEntry:%d, pHisto:%p, elems: %p",
285,023✔
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,412,511✔
2066
      if (colDataIsNull_f(pCol->nullbitmap, i)) {
2,127,570✔
2067
        continue;
822,996✔
2068
      }
2069
      numOfElems += 1;
1,304,574✔
2070
      char* data = colDataGetData(pCol, i);
1,304,574!
2071

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

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

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

2089
static int32_t apercentileTransferInfo(SAPercentileInfo* pInput, SAPercentileInfo* pOutput, bool* hasRes) {
8,737✔
2090
  pOutput->percent = pInput->percent;
8,737✔
2091
  pOutput->algo = pInput->algo;
8,737✔
2092
  if (pOutput->algo == APERCT_ALGO_TDIGEST) {
8,737✔
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,644✔
2119
    if (pInput->pHisto->numOfElems <= 0) {
8,644✔
2120
      return TSDB_CODE_SUCCESS;
174✔
2121
    }
2122

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

2198
  if (pInfo->algo == APERCT_ALGO_TDIGEST) {
254,927✔
2199
    buildTDigestInfo(pInfo);
11,067✔
2200
    tdigestAutoFill(pInfo->pTDigest, COMPRESSION);
11,067✔
2201
    if (pInfo->pTDigest->size > 0) {
11,066!
2202
      pInfo->result = tdigestQuantile(pInfo->pTDigest, pInfo->percent / 100);
11,066✔
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);
243,860✔
2209
    if (pInfo->pHisto->numOfElems > 0) {
243,862✔
2210
      qDebug("%s get the final res, elements:%" PRId64 ", numOfEntry:%d, pHisto:%p, elems:%p", __FUNCTION__,
188,185✔
2211
             pInfo->pHisto->numOfElems, pInfo->pHisto->numOfEntries, pInfo->pHisto, pInfo->pHisto->elems);
2212

2213
      double  ratio[] = {pInfo->percent};
188,185✔
2214
      double* res = NULL;
188,185✔
2215
      int32_t code = tHistogramUniform(pInfo->pHisto, ratio, 1, &res);
188,185✔
2216
      if (TSDB_CODE_SUCCESS != code) {
188,196!
2217
        taosMemoryFree(res);
×
2218
        return code;
×
2219
      }
2220
      pInfo->result = *res;
188,196✔
2221
      // memcpy(pCtx->pOutput, res, sizeof(double));
2222
      taosMemoryFree(res);
188,196✔
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__,
55,677✔
2227
             pInfo->pHisto->numOfElems, pInfo->pHisto->numOfEntries);
2228
    }
2229
  }
2230

2231
  return functionFinalize(pCtx, pBlock);
254,950✔
2232
}
2233

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

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

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

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

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

2261
  taosMemoryFree(res);
8,398!
2262
  return code;
8,398✔
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) {
992✔
2308
  SResultRowEntryInfo* pEntry = (SResultRowEntryInfo*)pRes;
992✔
2309

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

2315
  SFirstLastRes* pResult = GET_ROWCELL_INTERBUF(pEntry);
992✔
2316
  if (pResult->hasResult) {
992✔
2317
    if (pResult->pkBytes > 0) {
913✔
2318
      pResult->pkData = pResult->buf + pResult->bytes;
6✔
2319
    } else {
2320
      pResult->pkData = NULL;
907✔
2321
    }
2322
    if (pResult->ts < pBlockInfo->window.skey) {
913✔
2323
      return FUNC_DATA_REQUIRED_NOT_LOAD;
197✔
2324
    } else if (pResult->ts == pBlockInfo->window.skey) {
716✔
2325
      if (NULL == pResult->pkData) {
197✔
2326
        return FUNC_DATA_REQUIRED_NOT_LOAD;
191✔
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;
519✔
2333
  } else {
2334
    return FUNC_DATA_REQUIRED_DATA_LOAD;
79✔
2335
  }
2336
}
2337

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

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

2346
  SFirstLastRes* pResult = GET_ROWCELL_INTERBUF(pEntry);
1,459✔
2347
  if (pResult->hasResult) {
1,459✔
2348
    if (pResult->pkBytes > 0) {
1,365✔
2349
      pResult->pkData = pResult->buf + pResult->bytes;
5✔
2350
    } else {
2351
      pResult->pkData = NULL;
1,360✔
2352
    }
2353
    if (pResult->ts > pBlockInfo->window.ekey) {
1,365✔
2354
      return FUNC_DATA_REQUIRED_NOT_LOAD;
377✔
2355
    } else if (pResult->ts == pBlockInfo->window.ekey && pResult->pkData) {
988✔
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;
988✔
2361
  } else {
2362
    return FUNC_DATA_REQUIRED_DATA_LOAD;
94✔
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; }
25,120,862✔
2368

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

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

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

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

2394
  return *(TSKEY*)colDataGetData(pTsColInfo, rowIndex);
110,084,517!
2395
}
2396

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

2405
  SFirstLastRes*        pRes = GET_ROWCELL_INTERBUF(pResInfo);
2,529,225✔
2406
  SInputColumnInfoData* pInput = &pCtx->input;
2,529,225✔
2407

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

2413
static int32_t prepareBuf(SqlFunctionCtx* pCtx) {
405,379✔
2414
  if (pCtx->subsidiaries.rowLen == 0) {
405,379✔
2415
    int32_t rowLen = 0;
16,267✔
2416
    for (int32_t j = 0; j < pCtx->subsidiaries.num; ++j) {
37,907✔
2417
      SqlFunctionCtx* pc = pCtx->subsidiaries.pCtx[j];
21,640✔
2418
      rowLen += pc->pExpr->base.resSchema.bytes;
21,640✔
2419
    }
2420

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

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

2434
  if (pCtx->subsidiaries.num <= 0) {
60,479,802!
2435
    return TSDB_CODE_SUCCESS;
60,483,146✔
2436
  }
2437

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

2444
  return code;
11,715✔
2445
}
2446

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

2452
  if (IS_VAR_DATA_TYPE(type)) {
35,516,059!
2453
    if (type == TSDB_DATA_TYPE_JSON) {
543,051!
2454
      pInfo->bytes = getJsonValueLen(pData);
×
2455
    } else {
2456
      pInfo->bytes = varDataTLen(pData);
543,051✔
2457
    }
2458
  }
2459

2460
  (void)memcpy(pInfo->buf, pData, pInfo->bytes);
35,516,059✔
2461
  if (pkData != NULL) {
35,516,059✔
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;
35,516,059✔
2474
  int32_t code = firstlastSaveTupleData(pCtx->pSrcBlock, rowIndex, pCtx, pInfo, false);
35,516,059✔
2475
  if (code != TSDB_CODE_SUCCESS) {
35,584,476!
2476
    return code;
×
2477
  }
2478

2479
  pInfo->hasResult = true;
35,584,476✔
2480
  return TSDB_CODE_SUCCESS;
35,584,476✔
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) {
29,782,247✔
2486
  int32_t numOfElems = 0;
29,782,247✔
2487

2488
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
29,782,247✔
2489
  SFirstLastRes*       pInfo = GET_ROWCELL_INTERBUF(pResInfo);
29,782,247✔
2490

2491
  SInputColumnInfoData* pInput = &pCtx->input;
29,782,247✔
2492
  SColumnInfoData*      pInputCol = pInput->pData[0];
29,782,247✔
2493

2494
  pInfo->bytes = pInputCol->info.bytes;
29,782,247✔
2495

2496
  if (IS_NULL_TYPE(pInputCol->info.type)) {
29,782,247✔
2497
    return TSDB_CODE_SUCCESS;
2,035✔
2498
  }
2499

2500
  SColumnInfoData* pkCol = pInput->pPrimaryKey;
29,780,212✔
2501
  pInfo->pkType = -1;
29,780,212✔
2502
  __compar_fn_t pkCompareFn = NULL;
29,780,212✔
2503
  if (pCtx->hasPrimaryKey) {
29,780,212✔
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) &&
29,830,031!
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;
29,830,031!
2522

2523
  TSKEY startKey = getRowPTs(pInput->pPTS, 0);
29,830,031!
2524
  TSKEY endKey = getRowPTs(pInput->pPTS, pInput->totalRows - 1);
29,830,031!
2525

2526
  int32_t blockDataOrder = (startKey <= endKey) ? TSDB_ORDER_ASC : TSDB_ORDER_DESC;
29,830,031✔
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;
29,830,031✔
2580

2581
  int     from = -1;
29,830,031✔
2582
  int32_t i = -1;
29,830,031✔
2583
  while (funcInputGetNextRowIndex(pInput, from, true, &i, &from)) {
78,223,035✔
2584
    if (pInputCol->hasNull && colDataIsNull(pInputCol, pInput->totalRows, i, pColAgg)) {
62,507,016!
2585
      continue;
78,882✔
2586
    }
2587

2588
    numOfElems++;
48,343,965✔
2589
    char* data = colDataGetData(pInputCol, i);
48,343,965!
2590
    char* pkData = NULL;
48,343,965✔
2591
    if (pCtx->hasPrimaryKey) {
48,343,965✔
2592
      pkData = colDataGetData(pkCol, i);
153!
2593
    }
2594
    TSKEY cts = pts[i];
48,343,965✔
2595
    if (pResInfo->numOfRes == 0 || pInfo->ts > cts ||
48,343,965✔
2596
        (pInfo->ts == cts && pkCompareFn && pkCompareFn(pkData, pInfo->pkData) < 0)) {
29,504,313!
2597
      int32_t code = doSaveCurrentVal(pCtx, i, cts, pkData, pInputCol->info.type, data);
18,839,652✔
2598
      if (code != TSDB_CODE_SUCCESS) {
18,809,809!
2599
        return code;
×
2600
      }
2601
      pResInfo->numOfRes = 1;
18,809,809✔
2602
    }
2603
  }
2604
#endif
2605

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

2618
int32_t lastFunction(SqlFunctionCtx* pCtx) {
24,960,997✔
2619
  int32_t numOfElems = 0;
24,960,997✔
2620

2621
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
24,960,997✔
2622
  SFirstLastRes*       pInfo = GET_ROWCELL_INTERBUF(pResInfo);
24,960,997✔
2623

2624
  SInputColumnInfoData* pInput = &pCtx->input;
24,960,997✔
2625
  SColumnInfoData*      pInputCol = pInput->pData[0];
24,960,997✔
2626

2627
  int32_t type = pInputCol->info.type;
24,960,997✔
2628
  int32_t bytes = pInputCol->info.bytes;
24,960,997✔
2629
  pInfo->bytes = bytes;
24,960,997✔
2630

2631
  if (IS_NULL_TYPE(type)) {
24,960,997✔
2632
    return TSDB_CODE_SUCCESS;
2,035✔
2633
  }
2634

2635
  SColumnInfoData* pkCol = pInput->pPrimaryKey;
24,958,962✔
2636
  pInfo->pkType = -1;
24,958,962✔
2637
  __compar_fn_t pkCompareFn = NULL;
24,958,962✔
2638
  if (pCtx->hasPrimaryKey) {
24,958,962✔
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) &&
25,009,671!
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;
25,009,671!
2657

2658
  TSKEY startKey = getRowPTs(pInput->pPTS, 0);
25,009,671!
2659
  TSKEY endKey = getRowPTs(pInput->pPTS, pInput->totalRows - 1);
25,009,671!
2660

2661
  int32_t blockDataOrder = (startKey <= endKey) ? TSDB_ORDER_ASC : TSDB_ORDER_DESC;
25,009,671✔
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;
25,009,671✔
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) {
39,308,280✔
2717
    numOfElems = 1;
14,322,642✔
2718

2719
    int32_t round = pInput->numOfRows >> 2;
14,322,642✔
2720
    int32_t reminder = pInput->numOfRows & 0x03;
14,322,642✔
2721

2722
    for (int32_t i = pInput->startRowIndex, tick = 0; tick < round; i += 4, tick += 1) {
23,021,421✔
2723
      int64_t cts = pts[i];
8,692,842✔
2724
      int32_t chosen = i;
8,692,842✔
2725

2726
      if (cts < pts[i + 1]) {
8,692,842✔
2727
        cts = pts[i + 1];
4,827,885✔
2728
        chosen = i + 1;
4,827,885✔
2729
      }
2730

2731
      if (cts < pts[i + 2]) {
8,692,842✔
2732
        cts = pts[i + 2];
4,827,950✔
2733
        chosen = i + 2;
4,827,950✔
2734
      }
2735

2736
      if (cts < pts[i + 3]) {
8,692,842✔
2737
        cts = pts[i + 3];
4,827,247✔
2738
        chosen = i + 3;
4,827,247✔
2739
      }
2740

2741
      if (pResInfo->numOfRes == 0 || pInfo->ts < cts) {
8,692,842✔
2742
        char*   data = colDataGetData(pInputCol, chosen);
3,496,704!
2743
        int32_t code = doSaveCurrentVal(pCtx, i, cts, NULL, type, data);
3,496,704✔
2744
        if (code != TSDB_CODE_SUCCESS) {
3,502,641!
2745
          return code;
×
2746
        }
2747
        pResInfo->numOfRes = 1;
3,502,641✔
2748
      }
2749
    }
2750

2751
    for (int32_t i = pInput->startRowIndex + round * 4; i < pInput->startRowIndex + pInput->numOfRows; ++i) {
30,034,082✔
2752
      if (pResInfo->numOfRes == 0 || pInfo->ts < pts[i]) {
15,735,473✔
2753
        char*   data = colDataGetData(pInputCol, i);
7,369,333!
2754
        int32_t code = doSaveCurrentVal(pCtx, i, pts[i], NULL, type, data);
7,369,333✔
2755
        if (code != TSDB_CODE_SUCCESS) {
7,339,363!
2756
          return code;
×
2757
        }
2758
        pResInfo->numOfRes = 1;
7,339,363✔
2759
      }
2760
    }
2761
  } else {
2762
    int     from = -1;
10,687,029✔
2763
    int32_t i = -1;
10,687,029✔
2764
    while (funcInputGetNextRowIndex(pInput, from, false, &i, &from)) {
202,477,604✔
2765
      if (colDataIsNull(pInputCol, pInput->totalRows, i, pColAgg)) {
383,592,504✔
2766
        continue;
9,337,626✔
2767
      }
2768

2769
      numOfElems++;
182,458,626✔
2770
      char* pkData = NULL;
182,458,626✔
2771
      if (pCtx->hasPrimaryKey) {
182,458,626✔
2772
        pkData = colDataGetData(pkCol, i);
100,000,193!
2773
      }
2774
      if (pResInfo->numOfRes == 0 || pInfo->ts < pts[i] ||
182,458,626✔
2775
          (pInfo->ts == pts[i] && pkCompareFn && pkCompareFn(pkData, pInfo->pkData) < 0)) {
176,779,096!
2776
        char*   data = colDataGetData(pInputCol, i);
5,825,637!
2777
        int32_t code = doSaveCurrentVal(pCtx, i, pts[i], pkData, type, data);
5,825,637✔
2778
        if (code != TSDB_CODE_SUCCESS) {
5,819,960!
2779
          return code;
×
2780
        }
2781
        pResInfo->numOfRes = 1;
5,819,960✔
2782
      }
2783
    }
2784
  }
2785
#endif
2786

2787
#endif
2788

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

2798
  return TSDB_CODE_SUCCESS;
25,063,987✔
2799
}
2800

2801
static bool firstLastTransferInfoImpl(SFirstLastRes* pInput, SFirstLastRes* pOutput, bool isFirst) {
21,031,276✔
2802
  if (!pInput->hasResult) {
21,031,276✔
2803
    return false;
2✔
2804
  }
2805
  __compar_fn_t pkCompareFn = NULL;
21,031,274✔
2806
  if (pInput->pkData) {
21,031,274✔
2807
    pkCompareFn = getKeyComparFunc(pInput->pkType, (isFirst) ? TSDB_ORDER_ASC : TSDB_ORDER_DESC);
52✔
2808
  }
2809
  if (pOutput->hasResult) {
21,031,274✔
2810
    if (isFirst) {
13,301,846✔
2811
      if (pInput->ts > pOutput->ts ||
8,571,756✔
2812
          (pInput->ts == pOutput->ts && pkCompareFn && pkCompareFn(pInput->pkData, pOutput->pkData) > 0)) {
8,571,194!
2813
        return false;
562✔
2814
      }
2815
    } else {
2816
      if (pInput->ts < pOutput->ts ||
4,730,090✔
2817
          (pInput->ts == pOutput->ts && pkCompareFn && pkCompareFn(pInput->pkData, pOutput->pkData) > 0)) {
4,648,101!
2818
        return false;
81,989✔
2819
      }
2820
    }
2821
  }
2822

2823
  pOutput->isNull = pInput->isNull;
20,948,723✔
2824
  pOutput->ts = pInput->ts;
20,948,723✔
2825
  pOutput->bytes = pInput->bytes;
20,948,723✔
2826
  pOutput->pkType = pInput->pkType;
20,948,723✔
2827

2828
  (void)memcpy(pOutput->buf, pInput->buf, pOutput->bytes);
20,948,723✔
2829
  if (pInput->pkData) {
20,948,723✔
2830
    pOutput->pkBytes = pInput->pkBytes;
46✔
2831
    (void)memcpy(pOutput->buf + pOutput->bytes, pInput->pkData, pOutput->pkBytes);
46✔
2832
    pOutput->pkData = pOutput->buf + pOutput->bytes;
46✔
2833
  }
2834
  return true;
20,948,723✔
2835
}
2836

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

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

2853
  if (IS_NULL_TYPE(pCol->info.type)) {
7,746,094!
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,746,094!
2859
    return TSDB_CODE_FUNC_FUNTION_PARA_TYPE;
×
2860
  }
2861

2862
  SFirstLastRes* pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
7,746,094✔
2863

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

2867
  for (int32_t i = start; i < start + pInput->numOfRows; ++i) {
31,062,705✔
2868
    if (colDataIsNull_s(pCol, i)) {
46,633,222✔
2869
      continue;
2,285,341✔
2870
    }
2871
    char*          data = colDataGetData(pCol, i);
21,031,270!
2872
    SFirstLastRes* pInputInfo = (SFirstLastRes*)varDataVal(data);
21,031,270✔
2873
    if (pCtx->hasPrimaryKey) {
21,031,270✔
2874
      pInputInfo->pkData = pInputInfo->buf + pInputInfo->bytes;
52✔
2875
    } else {
2876
      pInputInfo->pkData = NULL;
21,031,218✔
2877
    }
2878

2879
    int32_t code = firstLastTransferInfo(pCtx, pInputInfo, pInfo, isFirstQuery, i);
21,031,270✔
2880
    if (code != TSDB_CODE_SUCCESS) {
21,031,270!
2881
      return code;
×
2882
    }
2883
    if (!numOfElems) {
21,031,270✔
2884
      numOfElems = pInputInfo->hasResult ? 1 : 0;
7,738,077✔
2885
    }
2886
  }
2887

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

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

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

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

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

2912
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
9,288,895✔
2913
  pResInfo->isNullRes = (pResInfo->numOfRes == 0) ? 1 : 0;
9,288,895✔
2914

2915
  SFirstLastRes* pRes = GET_ROWCELL_INTERBUF(pResInfo);
9,288,895✔
2916

2917
  if (pResInfo->isNullRes) {
9,288,895✔
2918
    colDataSetNULL(pCol, pBlock->info.rows);
32,414✔
2919
    return setSelectivityValue(pCtx, pBlock, &pRes->nullTuplePos, pBlock->info.rows);
32,414✔
2920
  }
2921
  code = colDataSetVal(pCol, pBlock->info.rows, pRes->buf, pRes->isNull || pResInfo->isNullRes);
9,256,481!
2922
  if (TSDB_CODE_SUCCESS != code) {
9,256,483!
2923
    return code;
×
2924
  }
2925

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

2929
  return code;
9,256,484✔
2930
}
2931

2932
int32_t firstLastPartialFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
24,957,974✔
2933
  int32_t code = TSDB_CODE_SUCCESS;
24,957,974✔
2934

2935
  SResultRowEntryInfo* pEntryInfo = GET_RES_INFO(pCtx);
24,957,974✔
2936
  SFirstLastRes*       pRes = GET_ROWCELL_INTERBUF(pEntryInfo);
24,957,974✔
2937

2938
  int32_t resultBytes = getFirstLastInfoSize(pRes->bytes, pRes->pkBytes);
24,957,974✔
2939

2940
  // todo check for failure
2941
  char* res = taosMemoryCalloc(resultBytes + VARSTR_HEADER_SIZE, sizeof(char));
24,884,814!
2942
  if (NULL == res) {
25,210,734!
2943
    return terrno;
×
2944
  }
2945
  (void)memcpy(varDataVal(res), pRes, resultBytes);
25,210,734✔
2946

2947
  varDataSetLen(res, resultBytes);
25,210,734✔
2948

2949
  int32_t          slotId = pCtx->pExpr->base.resSchema.slotId;
25,210,734✔
2950
  SColumnInfoData* pCol = taosArrayGet(pBlock->pDataBlock, slotId);
25,210,734✔
2951
  if (NULL == pCol) {
25,137,521!
2952
    taosMemoryFree(res);
×
2953
    return TSDB_CODE_OUT_OF_RANGE;
×
2954
  }
2955

2956
  if (pEntryInfo->numOfRes == 0) {
25,155,118✔
2957
    colDataSetNULL(pCol, pBlock->info.rows);
2,364,867!
2958
    code = setSelectivityValue(pCtx, pBlock, &pRes->nullTuplePos, pBlock->info.rows);
2,364,867✔
2959
  } else {
2960
    code = colDataSetVal(pCol, pBlock->info.rows, res, false);
22,790,251✔
2961
    if (TSDB_CODE_SUCCESS != code) {
22,565,090!
2962
      taosMemoryFree(res);
×
2963
      return code;
×
2964
    }
2965
    code = setSelectivityValue(pCtx, pBlock, &pRes->pos, pBlock->info.rows);
22,565,090✔
2966
  }
2967
  taosMemoryFree(res);
24,925,185!
2968
  return code;
25,292,827✔
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,868✔
2986
  SInputColumnInfoData* pInput = &pCtx->input;
11,868✔
2987
  SColumnInfoData*      pInputCol = pInput->pData[0];
11,868✔
2988
  SColumnInfoData*      pkCol = pInput->pPrimaryKey;
11,868✔
2989

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

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

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

3006
  if (pCtx->hasPrimaryKey && !colDataIsNull_s(pkCol, rowIndex)) {
11,941!
3007
    char* pkData = colDataGetData(pkCol, rowIndex);
73!
3008
    if (IS_VAR_DATA_TYPE(pInfo->pkType)) {
73!
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);
73✔
3016
    pInfo->pkData = pInfo->buf + pInfo->bytes;
73✔
3017
  }
3018
  pInfo->ts = cts;
11,868✔
3019
  int32_t code = firstlastSaveTupleData(pCtx->pSrcBlock, rowIndex, pCtx, pInfo, false);
11,868✔
3020
  if (code != TSDB_CODE_SUCCESS) {
11,863!
3021
    return code;
×
3022
  }
3023

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

3026
  return TSDB_CODE_SUCCESS;
11,863✔
3027
}
3028

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

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

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

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

3042
  if (IS_NULL_TYPE(type)) {
27,051✔
3043
    return TSDB_CODE_SUCCESS;
24✔
3044
  }
3045
  SColumnInfoData* pkCol = pInput->pPrimaryKey;
27,027✔
3046
  pInfo->pkType = -1;
27,027✔
3047
  __compar_fn_t pkCompareFn = NULL;
27,027✔
3048
  if (pCtx->hasPrimaryKey) {
27,027✔
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);
27,051!
3054
  TSKEY endKey = getRowPTs(pInput->pPTS, pInput->totalRows - 1);
27,051!
3055

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

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

3068
      break;
23,131✔
3069
    }
3070
  } else if (!pCtx->hasPrimaryKey && pCtx->order == TSDB_ORDER_DESC) {
3,931✔
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,757!
3074
      bool  isNull = colDataIsNull(pInputCol, pInput->numOfRows, i, NULL);
3,882✔
3075
      char* data = isNull ? NULL : colDataGetData(pInputCol, i);
3,882!
3076
      TSKEY cts = getRowPTs(pInput->pPTS, i);
3,882✔
3077
      numOfElems++;
3,882✔
3078

3079
      if (pResInfo->numOfRes == 0 || pInfo->ts < cts) {
3,882✔
3080
        int32_t code = doSaveLastrow(pCtx, data, i, cts, pInfo);
3,701✔
3081
        if (code != TSDB_CODE_SUCCESS) return code;
3,697!
3082
      }
3083
      break;
3,878✔
3084
    }
3085
  } else {
3086
    int64_t* pts = (int64_t*)pInput->pPTS->pData;
52✔
3087
    int      from = -1;
52✔
3088
    int32_t  i = -1;
52✔
3089
    while (funcInputGetNextRowIndex(pInput, from, false, &i, &from)) {
8,875✔
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);
27,024!
3111
  return TSDB_CODE_SUCCESS;
27,024✔
3112
}
3113

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

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

3139
static int32_t doSetPrevVal(SDiffInfo* pDiffInfo, int32_t type, const char* pv, int64_t ts) {
33,741✔
3140
  switch (type) {
33,741!
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:
308✔
3145
    case TSDB_DATA_TYPE_TINYINT:
3146
      pDiffInfo->prev.i64 = *(int8_t*)pv;
308✔
3147
      break;
308✔
3148
    case TSDB_DATA_TYPE_UINT:
32,237✔
3149
    case TSDB_DATA_TYPE_INT:
3150
      pDiffInfo->prev.i64 = *(int32_t*)pv;
32,237✔
3151
      break;
32,237✔
3152
    case TSDB_DATA_TYPE_USMALLINT:
256✔
3153
    case TSDB_DATA_TYPE_SMALLINT:
3154
      pDiffInfo->prev.i64 = *(int16_t*)pv;
256✔
3155
      break;
256✔
3156
    case TSDB_DATA_TYPE_TIMESTAMP:
305✔
3157
    case TSDB_DATA_TYPE_UBIGINT:
3158
    case TSDB_DATA_TYPE_BIGINT:
3159
      pDiffInfo->prev.i64 = *(int64_t*)pv;
305✔
3160
      break;
305✔
3161
    case TSDB_DATA_TYPE_FLOAT:
200✔
3162
      pDiffInfo->prev.d64 = *(float*)pv;
200✔
3163
      break;
200✔
3164
    case TSDB_DATA_TYPE_DOUBLE:
410✔
3165
      pDiffInfo->prev.d64 = *(double*)pv;
410✔
3166
      break;
410✔
3167
    default:
×
3168
      return TSDB_CODE_FUNC_FUNTION_PARA_TYPE;
×
3169
  }
3170
  pDiffInfo->prevTs = ts;
33,741✔
3171
  pDiffInfo->hasPrev = true;
33,741✔
3172
  return TSDB_CODE_SUCCESS;
33,741✔
3173
}
3174

3175
static bool diffIsNegtive(SDiffInfo* pDiffInfo, int32_t type, const char* pv) {
33,377✔
3176
  switch (type) {
33,377!
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: {
3,812✔
3182
      int64_t v = *(int32_t*)pv;
3,812✔
3183
      return v < pDiffInfo->prev.i64;
3,812✔
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,433✔
3194
      int64_t v = *(int8_t*)pv;
5,433✔
3195
      return v < pDiffInfo->prev.i64;
5,433✔
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: {
5,880✔
3202
      int64_t v = *(int16_t*)pv;
5,880✔
3203
      return v < pDiffInfo->prev.i64;
5,880✔
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,421✔
3210
    case TSDB_DATA_TYPE_BIGINT: {
3211
      int64_t v = *(int64_t*)pv;
7,421✔
3212
      return v < pDiffInfo->prev.i64;
7,421✔
3213
    }
3214
    case TSDB_DATA_TYPE_FLOAT: {
3,732✔
3215
      float v = *(float*)pv;
3,732✔
3216
      return v < pDiffInfo->prev.d64;
3,732✔
3217
    }
3218
    case TSDB_DATA_TYPE_DOUBLE: {
7,075✔
3219
      double v = *(double*)pv;
7,075✔
3220
      return v < pDiffInfo->prev.d64;
7,075✔
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) {
16,999,971✔
3230
  bool isNegative = v < pDiffInfo->prev.i64;
16,999,971✔
3231
  if (type == TSDB_DATA_TYPE_UBIGINT) {
16,999,971✔
3232
    isNegative = (uint64_t)v < (uint64_t)pDiffInfo->prev.i64;
453✔
3233
  }
3234
  int64_t delta = v - pDiffInfo->prev.i64;
16,999,971✔
3235
  if (isNegative && ignoreNegative(pDiffInfo->ignoreOption)) {
16,999,971✔
3236
    colDataSetNull_f_s(pOutput, pos);
11,092✔
3237
    pOutput->hasNull = true;
11,092✔
3238
  } else {
3239
    colDataSetInt64(pOutput, pos, &delta);
16,988,879✔
3240
  }
3241
  pDiffInfo->prev.i64 = v;
16,999,971✔
3242
}
16,999,971✔
3243

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

3254
static int32_t doHandleDiff(SDiffInfo* pDiffInfo, int32_t type, const char* pv, SColumnInfoData* pOutput, int32_t pos,
17,095,837✔
3255
                            int64_t ts) {
3256
  if (!pDiffInfo->hasPrev) {
17,095,837✔
3257
    colDataSetNull_f_s(pOutput, pos);
443✔
3258
    return doSetPrevVal(pDiffInfo, type, pv, ts);
443✔
3259
  }
3260
  pDiffInfo->prevTs = ts;
17,095,394✔
3261
  switch (type) {
17,095,394!
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,779,760✔
3268
      int64_t v = *(int32_t*)pv;
15,779,760✔
3269
      tryToSetInt64(pDiffInfo, type, pOutput, v, pos);
15,779,760✔
3270
      break;
15,779,760✔
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: {
34,248✔
3283
      int64_t v = *(int8_t*)pv;
34,248✔
3284
      tryToSetInt64(pDiffInfo, type, pOutput, v, pos);
34,248✔
3285
      break;
34,248✔
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: {
33,651✔
3293
      int64_t v = *(int16_t*)pv;
33,651✔
3294
      tryToSetInt64(pDiffInfo, type, pOutput, v, pos);
33,651✔
3295
      break;
33,651✔
3296
    }
3297
    case TSDB_DATA_TYPE_TIMESTAMP:
1,140,531✔
3298
    case TSDB_DATA_TYPE_UBIGINT:
3299
    case TSDB_DATA_TYPE_BIGINT: {
3300
      int64_t v = *(int64_t*)pv;
1,140,531✔
3301
      tryToSetInt64(pDiffInfo, type, pOutput, v, pos);
1,140,531✔
3302
      break;
1,140,531✔
3303
    }
3304
    case TSDB_DATA_TYPE_FLOAT: {
44,337✔
3305
      double v = *(float*)pv;
44,337✔
3306
      tryToSetDouble(pDiffInfo, pOutput, v, pos);
44,337✔
3307
      break;
44,337✔
3308
    }
3309
    case TSDB_DATA_TYPE_DOUBLE: {
51,086✔
3310
      double v = *(double*)pv;
51,086✔
3311
      tryToSetDouble(pDiffInfo, pOutput, v, pos);
51,086✔
3312
      break;
51,086✔
3313
    }
3314
    default:
×
3315
      return TSDB_CODE_FUNC_FUNTION_PARA_TYPE;
×
3316
  }
3317
  pDiffInfo->hasPrev = true;
17,095,394✔
3318
  return TSDB_CODE_SUCCESS;
17,095,394✔
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,
279,904,607✔
3324
                              int32_t* nextFrom) {
3325
  if (pInput->pPrimaryKey == NULL) {
279,904,607✔
3326
    if (from == -1) {
179,958,756✔
3327
      from = pInput->startRowIndex;
41,630,787✔
3328
    } else if (from >= pInput->numOfRows + pInput->startRowIndex) {
138,327,969✔
3329
      return false;
41,344,585✔
3330
    }
3331
    *pRowIndex = from;
138,614,171✔
3332
    *nextFrom = from + 1;
138,614,171✔
3333
    return true;
138,614,171✔
3334
  } else {
3335
    if (from == -1) {
99,945,851✔
3336
      from = pInput->startRowIndex;
30,175✔
3337
    } else if (from >= pInput->numOfRows + pInput->startRowIndex) {
99,915,676✔
3338
      return false;
30,175✔
3339
    }
3340
    TSKEY*           tsList = (int64_t*)pInput->pPTS->pData;
99,915,676✔
3341
    SColumnInfoData* pkCol = pInput->pPrimaryKey;
99,915,676✔
3342
    int8_t           pkType = pkCol->info.type;
99,915,676✔
3343
    int32_t          order = (firstOccur) ? TSDB_ORDER_ASC : TSDB_ORDER_DESC;
99,915,676✔
3344
    __compar_fn_t    compareFunc = getKeyComparFunc(pkType, order);
99,915,676✔
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) {
17,218,846✔
3367
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
17,218,846✔
3368
  SDiffInfo*           pDiffInfo = GET_ROWCELL_INTERBUF(pResInfo);
17,218,846✔
3369

3370
  if (pRow->isDataNull || !pDiffInfo->hasPrev) {
17,218,846✔
3371
    return true;
123,380✔
3372
  } else if (ignoreNegative(pDiffInfo->ignoreOption)) {
17,095,466✔
3373
    return diffIsNegtive(pDiffInfo, pCtx->input.pData[0]->info.type, pRow->pData);
33,377✔
3374
  }
3375
  return false;
17,062,089✔
3376
}
3377

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

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

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

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

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

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

3413
    // handle selectivity
3414
    if (pCtx->subsidiaries.num > 0) {
88,042✔
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;
88,042✔
3421
  }
3422

3423
  char* pv = pRow->pData;
17,095,858✔
3424

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

3440
  return TSDB_CODE_SUCCESS;
17,095,837✔
3441
}
3442

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

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

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

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

3473
  SqlFunctionCtx* pCtx0 = *(SqlFunctionCtx**)taosArrayGet(pCtxArray, 0);
224,430✔
3474
  SFuncInputRow*  pRow0 = (SFuncInputRow*)taosArrayGet(pRows, 0);
224,430✔
3475
  if (NULL == pCtx0 || NULL == pRow0) {
224,430!
3476
    code = terrno;
×
3477
    goto _exit;
×
3478
  }
3479
  int32_t startOffset = pCtx0->offset;
224,430✔
3480
  bool    result = false;
224,430✔
3481
  while (1) {
17,204,331✔
3482
    code = funcInputGetNextRow(pCtx0, pRow0, &result);
17,428,761✔
3483
    if (TSDB_CODE_SUCCESS != code) {
17,428,761!
3484
      goto _exit;
×
3485
    }
3486
    if (!result) {
17,428,761✔
3487
      break;
224,409✔
3488
    }
3489
    bool hasNotNullValue = !diffResultIsNull(pCtx0, pRow0);
17,204,352✔
3490
    for (int i = 1; i < diffColNum; ++i) {
17,218,846✔
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;
17,204,352✔
3511

3512
    bool newRow = false;
17,204,352✔
3513
    for (int i = 0; i < diffColNum; ++i) {
34,423,177✔
3514
      SqlFunctionCtx* pCtx = *(SqlFunctionCtx**)taosArrayGet(pCtxArray, i);
17,218,846✔
3515
      SFuncInputRow*  pRow = (SFuncInputRow*)taosArrayGet(pRows, i);
17,218,846✔
3516
      if (NULL == pCtx || NULL == pRow) {
17,218,846!
3517
        code = terrno;
×
3518
        goto _exit;
×
3519
      }
3520
      if ((keepNull || hasNotNullValue) && !isFirstRow(pCtx, pRow)) {
17,218,846✔
3521
        code = setDoDiffResult(pCtx, pRow, pos);
17,183,900✔
3522
        if (code != TSDB_CODE_SUCCESS) {
17,183,900✔
3523
          goto _exit;
21✔
3524
        }
3525
        newRow = true;
17,183,879✔
3526
      } else {
3527
        code = trySetPreVal(pCtx, pRow);
34,946✔
3528
        if (code != TSDB_CODE_SUCCESS) {
34,946!
3529
          goto _exit;
×
3530
        }
3531
      }
3532
    }
3533
    if (newRow) ++numOfElems;
17,204,331✔
3534
  }
3535

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

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

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

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

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

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

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

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

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

3585
  return pRes;
475,252✔
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,664✔
3594
  int32_t              numOfElems = 0;
23,664✔
3595
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
23,664✔
3596

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

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

3603
  int32_t start = pInput->startRowIndex;
23,667✔
3604
  for (int32_t i = start; i < pInput->numOfRows + start; ++i) {
368,444✔
3605
    if (pCol->hasNull && colDataIsNull_f(pCol->nullbitmap, i)) {
344,483✔
3606
      continue;
24,870✔
3607
    }
3608

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

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

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

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

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

3637
  int32_t start = pInput->startRowIndex;
3,100✔
3638
  for (int32_t i = start; i < pInput->numOfRows + start; ++i) {
132,339✔
3639
    if (pCol->hasNull && colDataIsNull_f(pCol->nullbitmap, i)) {
129,326✔
3640
      continue;
23,837✔
3641
    }
3642

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

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

3659
  return TSDB_CODE_SUCCESS;
3,013✔
3660
}
3661

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

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

3668
  if (IS_SIGNED_NUMERIC_TYPE(type)) {
1,485,542!
3669
    if (val1->v.i == val2->v.i) {
808,502✔
3670
      return 0;
164,381✔
3671
    }
3672

3673
    return (val1->v.i > val2->v.i) ? 1 : -1;
644,121✔
3674
  } else if (IS_UNSIGNED_NUMERIC_TYPE(type)) {
677,040!
3675
    if (val1->v.u == val2->v.u) {
460,791✔
3676
      return 0;
99,942✔
3677
    }
3678

3679
    return (val1->v.u > val2->v.u) ? 1 : -1;
360,849✔
3680
  } else if (TSDB_DATA_TYPE_FLOAT == type) {
216,249✔
3681
    if (val1->v.f == val2->v.f) {
28,445✔
3682
      return 0;
63✔
3683
    }
3684

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

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

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

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

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

3703
  STopBotResItem* pItems = pRes->pItems;
424,817✔
3704

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

3711
    // save the data of this tuple
3712
    if (pCtx->subsidiaries.num > 0) {
112,652✔
3713
      code = saveTupleData(pCtx, rowIndex, pSrcBlock, &pItem->tuplePos);
45,676✔
3714
      if (code != TSDB_CODE_SUCCESS) {
45,636!
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++;
112,612✔
3724
    code = taosheapsort((void*)pItems, sizeof(STopBotResItem), pEntryInfo->numOfRes, (const void*)&type,
112,612✔
3725
                        topBotResComparFn, !isTopQuery);
112,612✔
3726
    if (code != TSDB_CODE_SUCCESS) {
112,882!
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) ||
312,165!
3731
                        (IS_UNSIGNED_NUMERIC_TYPE(type) && val.u > pItems[0].v.u) ||
161,074!
3732
                        (TSDB_DATA_TYPE_FLOAT == type && val.f > pItems[0].v.f) ||
106,531✔
3733
                        (TSDB_DATA_TYPE_DOUBLE == type && val.d > pItems[0].v.d))) ||
105,376✔
3734
        (!isTopQuery && ((IS_SIGNED_NUMERIC_TYPE(type) && val.i < pItems[0].v.i) ||
173,302!
3735
                         (IS_UNSIGNED_NUMERIC_TYPE(type) && val.u < pItems[0].v.u) ||
80,669!
3736
                         (TSDB_DATA_TYPE_FLOAT == type && val.f < pItems[0].v.f) ||
79,663✔
3737
                         (TSDB_DATA_TYPE_DOUBLE == type && val.d < pItems[0].v.d)))) {
78,599✔
3738
      // replace the old data and the coresponding tuple data
3739
      STopBotResItem* pItem = &pItems[0];
148,405✔
3740
      pItem->v = val;
148,405✔
3741
      pItem->uid = uid;
148,405✔
3742

3743
      // save the data of this tuple by over writing the old data
3744
      if (pCtx->subsidiaries.num > 0) {
148,405✔
3745
        code = updateTupleData(pCtx, rowIndex, pSrcBlock, &pItem->tuplePos);
117,451✔
3746
        if (code != TSDB_CODE_SUCCESS) {
116,953!
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,
147,907✔
3754
                            topBotResComparFn, NULL, !isTopQuery);
147,907✔
3755
      if (code != TSDB_CODE_SUCCESS) {
148,707!
3756
        return code;
×
3757
      }
3758
    }
3759
  }
3760

3761
  return TSDB_CODE_SUCCESS;
425,349✔
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,
405,361✔
3771
                           char* buf, char** res) {
3772
  char* nullList = buf;
405,361✔
3773
  char* pStart = (char*)(nullList + sizeof(bool) * pSubsidiaryies->num);
405,361✔
3774

3775
  int32_t offset = 0;
405,361✔
3776
  for (int32_t i = 0; i < pSubsidiaryies->num; ++i) {
861,024✔
3777
    SqlFunctionCtx* pc = pSubsidiaryies->pCtx[i];
455,661✔
3778

3779
    // group_key function has its own process function
3780
    // do not process there
3781
    if (fmIsGroupKeyFunc(pc->functionId)) {
455,661✔
3782
      continue;
40,168✔
3783
    }
3784

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

3788
    SColumnInfoData* pCol = taosArrayGet(pSrcBlock->pDataBlock, srcSlotId);
415,501✔
3789
    if (NULL == pCol) {
415,495!
3790
      return TSDB_CODE_OUT_OF_RANGE;
×
3791
    }
3792
    if ((nullList[i] = colDataIsNull_s(pCol, rowIndex)) == true) {
830,990✔
3793
      offset += pCol->info.bytes;
291✔
3794
      continue;
291✔
3795
    }
3796

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

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

3807
  *res = buf;
405,363✔
3808
  return TSDB_CODE_SUCCESS;
405,363✔
3809
}
3810

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

3817
    if (pHandle->currentPage == -1) {
628,653✔
3818
      pPage = getNewBufPage(pHandle->pBuf, &pHandle->currentPage);
19,230✔
3819
      if (pPage == NULL) {
19,230!
UNCOV
3820
        return terrno;
×
3821
      }
3822
      pPage->num = sizeof(SFilePage);
19,230✔
3823
    } else {
3824
      pPage = getBufPage(pHandle->pBuf, pHandle->currentPage);
609,423✔
3825
      if (pPage == NULL) {
608,895!
3826
        return terrno;
×
3827
      }
3828
      if (pPage->num + length > getBufPageSize(pHandle->pBuf)) {
608,895✔
3829
        // current page is all used, let's prepare a new buffer page
3830
        releaseBufPage(pHandle->pBuf, pPage);
1,595✔
3831
        pPage = getNewBufPage(pHandle->pBuf, &pHandle->currentPage);
1,595✔
3832
        if (pPage == NULL) {
1,595!
3833
          return terrno;
×
3834
        }
3835
        pPage->num = sizeof(SFilePage);
1,595✔
3836
      }
3837
    }
3838

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

3842
    pPage->num += length;
627,941✔
3843
    setBufPageDirty(pPage, true);
627,941✔
3844
    releaseBufPage(pHandle->pBuf, pPage);
627,612✔
3845
  } else {  // other tuple save policy
3846
    if (pStore->streamStateFuncPut(pHandle->pState, key, pBuf, length) >= 0) {
66,555!
3847
      p.streamTupleKey = *key;
66,557✔
3848
    }
3849
  }
3850

3851
  *pPos = p;
694,063✔
3852
  return TSDB_CODE_SUCCESS;
694,063✔
3853
}
3854

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

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

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

3882
static int32_t doUpdateTupleData(SSerializeDataHandle* pHandle, const void* pBuf, size_t length, STuplePos* pPos,
251,740✔
3883
                                 SFunctionStateStore* pStore) {
3884
  if (pHandle->pBuf != NULL) {
251,740✔
3885
    SFilePage* pPage = getBufPage(pHandle->pBuf, pPos->pageId);
135,189✔
3886
    if (pPage == NULL) {
135,028!
3887
      return terrno;
×
3888
    }
3889
    (void)memcpy(pPage->data + pPos->offset, pBuf, length);
135,028✔
3890
    setBufPageDirty(pPage, true);
135,028✔
3891
    releaseBufPage(pHandle->pBuf, pPage);
134,939✔
3892
  } else {
3893
    int32_t code = pStore->streamStateFuncPut(pHandle->pState, &pPos->streamTupleKey, pBuf, length);
116,551✔
3894
    if (TSDB_CODE_SUCCESS != code) {
116,553!
3895
      return code;
×
3896
    }
3897
  }
3898

3899
  return TSDB_CODE_SUCCESS;
251,303✔
3900
}
3901

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

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

3916
static int32_t doLoadTupleData(SSerializeDataHandle* pHandle, const STuplePos* pPos, SFunctionStateStore* pStore,
148,270✔
3917
                               char** value) {
3918
  if (pHandle->pBuf != NULL) {
148,270✔
3919
    SFilePage* pPage = getBufPage(pHandle->pBuf, pPos->pageId);
82,043✔
3920
    if (pPage == NULL) {
82,042!
3921
      *value = NULL;
×
3922
      return terrno;
×
3923
    }
3924
    *value = pPage->data + pPos->offset;
82,042✔
3925
    releaseBufPage(pHandle->pBuf, pPage);
82,042✔
3926
    return TSDB_CODE_SUCCESS;
82,036✔
3927
  } else {
3928
    *value = NULL;
66,227✔
3929
    int32_t vLen;
3930
    int32_t code = pStore->streamStateFuncGet(pHandle->pState, &pPos->streamTupleKey, (void**)(value), &vLen);
66,227✔
3931
    if (TSDB_CODE_SUCCESS != code) {
66,226!
3932
      return code;
×
3933
    }
3934
    return TSDB_CODE_SUCCESS;
66,226✔
3935
  }
3936
}
3937

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

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

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

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

3951
  SColumnInfoData* pCol = taosArrayGet(pBlock->pDataBlock, slotId);
24,396✔
3952
  if (NULL == pCol) {
24,396!
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,396✔
3958
  if (pEntryInfo->numOfRes <= 0) {
24,396✔
3959
    colDataSetNULL(pCol, currentRow);
514!
3960
    code = setSelectivityValue(pCtx, pBlock, &pRes->nullTuplePos, currentRow);
514✔
3961
    return code;
514✔
3962
  }
3963
  for (int32_t i = 0; i < pEntryInfo->numOfRes; ++i) {
136,739✔
3964
    STopBotResItem* pItem = &pRes->pItems[i];
112,853✔
3965
    code = colDataSetVal(pCol, currentRow, (const char*)&pItem->v.i, false);
112,853✔
3966
    if (TSDB_CODE_SUCCESS != code) {
112,860!
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);
112,860✔
3974
    if (TSDB_CODE_SUCCESS != code) {
112,857!
3975
      return code;
×
3976
    }
3977
    currentRow += 1;
112,857✔
3978
  }
3979

3980
  return code;
23,886✔
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,940✔
4057

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

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

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

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

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

4086
  SSpreadInfo* pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
280,799✔
4087

4088
  if (pInput->colDataSMAIsSet) {
280,799!
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];
280,799✔
4115

4116
    int32_t start = pInput->startRowIndex;
280,799✔
4117
    // check the valid data one by one
4118
    for (int32_t i = start; i < pInput->numOfRows + start; ++i) {
5,458,336✔
4119
      if (colDataIsNull_f(pCol->nullbitmap, i)) {
5,177,537✔
4120
        continue;
1,572,038✔
4121
      }
4122

4123
      char* data = colDataGetData(pCol, i);
3,605,499!
4124

4125
      double v = 0;
3,605,499✔
4126
      GET_TYPED_DATA(v, double, type, data);
3,605,499!
4127
      if (v < GET_DOUBLE_VAL(&pInfo->min)) {
3,605,499✔
4128
        SET_DOUBLE_VAL(&pInfo->min, v);
262,718✔
4129
      }
4130

4131
      if (v > GET_DOUBLE_VAL(&pInfo->max)) {
3,605,499✔
4132
        SET_DOUBLE_VAL(&pInfo->max, v);
518,359✔
4133
      }
4134

4135
      numOfElems += 1;
3,605,499✔
4136
    }
4137
  }
4138

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

4146
  return TSDB_CODE_SUCCESS;
280,799✔
4147
}
4148

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

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

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

4164
  if (IS_NULL_TYPE(pCol->info.type)) {
18,347!
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,347!
4170
    return TSDB_CODE_FUNC_FUNTION_PARA_TYPE;
×
4171
  }
4172

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

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

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

4189
  return TSDB_CODE_SUCCESS;
18,347✔
4190
}
4191

4192
int32_t spreadFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
237,964✔
4193
  SSpreadInfo* pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
237,964✔
4194
  if (pInfo->hasResult == true) {
237,964✔
4195
    SET_DOUBLE_VAL(&pInfo->result, pInfo->max - pInfo->min);
208,499✔
4196
  } else {
4197
    GET_RES_INFO(pCtx)->isNullRes = 1;
29,465✔
4198
  }
4199
  return functionFinalize(pCtx, pBlock);
237,964✔
4200
}
4201

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

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

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

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

4227
_exit:
22,343✔
4228
  taosMemoryFree(res);
22,343!
4229
  return code;
22,343✔
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,594✔
4247
  pEnv->calcMemSize = sizeof(SElapsedInfo);
18,594✔
4248
  return true;
18,594✔
4249
}
4250

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

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

4264
  if (pCtx->numOfParams > 1) {
36,322✔
4265
    pInfo->timeUnit = pCtx->param[1].param.i;
19,902✔
4266
  } else {
4267
    pInfo->timeUnit = 1;
16,420✔
4268
  }
4269

4270
  return TSDB_CODE_SUCCESS;
36,322✔
4271
}
4272

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

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

4280
  SElapsedInfo* pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
36,361✔
4281

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

4291
  if (pInput->colDataSMAIsSet) {
36,305!
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) {
36,305!
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];
36,305✔
4317

4318
    int32_t start = pInput->startRowIndex;
36,305✔
4319
    TSKEY*  ptsList = (int64_t*)colDataGetData(pCol, 0);
36,305!
4320
    if (pCtx->order == TSDB_ORDER_DESC) {
36,305✔
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) {
36,143✔
4335
        pInfo->min = (pInfo->min > ptsList[start]) ? ptsList[start] : pInfo->min;
34,085✔
4336
      } else {
4337
        pInfo->min = pCtx->start.key;
2,058✔
4338
      }
4339

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

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

4353
  return TSDB_CODE_SUCCESS;
36,361✔
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) {
36,384✔
4389
  SElapsedInfo* pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
36,384✔
4390
  double        result = (double)pInfo->max - (double)pInfo->min;
36,384✔
4391
  result = (result >= 0) ? result : -result;
36,384✔
4392
  pInfo->result = result / pInfo->timeUnit;
36,384✔
4393
  return functionFinalize(pCtx, pBlock);
36,384✔
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,668✔
4439
  return (int32_t)sizeof(SHistoFuncInfo) + HISTOGRAM_MAX_BINS_NUM * sizeof(SHistoFuncBin);
7,668✔
4440
}
4441

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

4447
static int8_t getHistogramBinType(char* binTypeStr) {
7,026✔
4448
  int8_t binType;
4449
  if (strcasecmp(binTypeStr, "user_input") == 0) {
7,026✔
4450
    binType = USER_INPUT_BIN;
3,829✔
4451
  } else if (strcasecmp(binTypeStr, "linear_bin") == 0) {
3,197✔
4452
    binType = LINEAR_BIN;
803✔
4453
  } else if (strcasecmp(binTypeStr, "log_bin") == 0) {
2,394!
4454
    binType = LOG_BIN;
2,394✔
4455
  } else {
4456
    binType = UNKNOWN_BIN;
×
4457
  }
4458

4459
  return binType;
7,026✔
4460
}
4461

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

4474
    cJSON* start = cJSON_GetObjectItem(binDesc, "start");
3,196✔
4475
    cJSON* factor = cJSON_GetObjectItem(binDesc, "factor");
3,197✔
4476
    cJSON* width = cJSON_GetObjectItem(binDesc, "width");
3,197✔
4477
    cJSON* count = cJSON_GetObjectItem(binDesc, "count");
3,197✔
4478
    cJSON* infinity = cJSON_GetObjectItem(binDesc, "infinity");
3,197✔
4479

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

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

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

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

4505
    intervals = taosMemoryCalloc(numOfBins, sizeof(double));
3,196!
4506
    if (NULL == intervals) {
3,197!
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) {
3,197!
4512
      // linear bin process
4513
      if (width->valuedouble == 0) {
803!
4514
        taosMemoryFree(intervals);
×
4515
        cJSON_Delete(binDesc);
×
4516
        return TSDB_CODE_FAILED;
×
4517
      }
4518
      for (int i = 0; i < counter + 1; ++i) {
3,317✔
4519
        intervals[startIndex] = start->valuedouble + i * width->valuedouble;
2,514✔
4520
        if (isinf(intervals[startIndex])) {
2,514!
4521
          taosMemoryFree(intervals);
×
4522
          cJSON_Delete(binDesc);
×
4523
          return TSDB_CODE_FAILED;
×
4524
        }
4525
        startIndex++;
2,514✔
4526
      }
4527
    } else if (cJSON_IsNumber(factor) && width == NULL && binType == LOG_BIN) {
2,394!
4528
      // log bin process
4529
      if (start->valuedouble == 0) {
2,394!
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,394!
4535
        taosMemoryFree(intervals);
×
4536
        cJSON_Delete(binDesc);
×
4537
        return TSDB_CODE_FAILED;
×
4538
      }
4539
      for (int i = 0; i < counter + 1; ++i) {
14,453✔
4540
        intervals[startIndex] = start->valuedouble * pow(factor->valuedouble, i * 1.0);
12,059✔
4541
        if (isinf(intervals[startIndex])) {
12,059!
4542
          taosMemoryFree(intervals);
×
4543
          cJSON_Delete(binDesc);
×
4544
          return TSDB_CODE_FAILED;
×
4545
        }
4546
        startIndex++;
12,059✔
4547
      }
4548
    } else {
4549
      taosMemoryFree(intervals);
×
4550
      cJSON_Delete(binDesc);
×
4551
      return TSDB_CODE_FAILED;
×
4552
    }
4553

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

4604
  pInfo->numOfBins = numOfBins - 1;
7,026✔
4605
  pInfo->normalized = normalized;
7,026✔
4606
  for (int32_t i = 0; i < pInfo->numOfBins; ++i) {
29,295✔
4607
    pInfo->bins[i].lower = intervals[i] < intervals[i + 1] ? intervals[i] : intervals[i + 1];
22,269✔
4608
    pInfo->bins[i].upper = intervals[i + 1] > intervals[i] ? intervals[i + 1] : intervals[i];
22,269✔
4609
    pInfo->bins[i].count = 0;
22,269✔
4610
  }
4611

4612
  taosMemoryFree(intervals);
7,026✔
4613
  cJSON_Delete(binDesc);
7,025✔
4614

4615
  return TSDB_CODE_SUCCESS;
7,026✔
4616
}
4617

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

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

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

4638
  if (binType == UNKNOWN_BIN) {
7,026!
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,026!
4642
  if (binDesc == NULL) {
7,026!
4643
    return terrno;
×
4644
  }
4645
  int64_t normalized = pCtx->param[3].param.i;
7,026✔
4646
  if (normalized != 0 && normalized != 1) {
7,026!
4647
    taosMemoryFree(binDesc);
×
4648
    return TSDB_CODE_FUNC_FUNTION_PARA_VALUE;
×
4649
  }
4650
  int32_t code = getHistogramBinDesc(pInfo, binDesc, binType, (bool)normalized);
7,026✔
4651
  if (TSDB_CODE_SUCCESS != code) {
7,026!
4652
    taosMemoryFree(binDesc);
×
4653
    return code;
×
4654
  }
4655
  taosMemoryFree(binDesc);
7,026!
4656

4657
  return TSDB_CODE_SUCCESS;
7,026✔
4658
}
4659

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

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

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

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

4671
  int32_t numOfElems = 0;
7,930✔
4672
  for (int32_t i = start; i < numOfRows + start; ++i) {
1,205,249✔
4673
    if (pCol->hasNull && colDataIsNull_f(pCol->nullbitmap, i)) {
1,197,319✔
4674
      continue;
709,714✔
4675
    }
4676

4677
    numOfElems++;
487,605✔
4678

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

4683
    for (int32_t k = 0; k < pInfo->numOfBins; ++k) {
1,268,098✔
4684
      if (v > pInfo->bins[k].lower && v <= pInfo->bins[k].upper) {
1,019,648✔
4685
        pInfo->bins[k].count++;
239,155✔
4686
        pInfo->totalCount++;
239,155✔
4687
        break;
239,155✔
4688
      }
4689
    }
4690
  }
4691

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

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

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

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

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

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

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

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

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

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

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

4748
  if (pInfo->normalized) {
6,927✔
4749
    for (int32_t k = 0; k < pResInfo->numOfRes; ++k) {
26,733✔
4750
      if (pInfo->totalCount != 0) {
20,556✔
4751
        pInfo->bins[k].percentage = pInfo->bins[k].count / (double)pInfo->totalCount;
4,797✔
4752
      } else {
4753
        pInfo->bins[k].percentage = 0;
15,759✔
4754
      }
4755
    }
4756
  }
4757

4758
  for (int32_t i = 0; i < pResInfo->numOfRes; ++i) {
28,758✔
4759
    int32_t len;
4760
    char    buf[512] = {0};
21,833✔
4761
    if (!pInfo->normalized) {
21,833✔
4762
      len = tsnprintf(varDataVal(buf), sizeof(buf) - VARSTR_HEADER_SIZE,
1,276✔
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,
20,557✔
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);
21,828✔
4771
    code = colDataSetVal(pCol, currentRow, buf, false);
21,828✔
4772
    if (TSDB_CODE_SUCCESS != code) {
21,831!
4773
      return code;
×
4774
    }
4775
    currentRow++;
21,831✔
4776
  }
4777

4778
  return code;
6,925✔
4779
}
4780

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

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

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

4802
_exit:
1,581✔
4803
  taosMemoryFree(res);
1,581!
4804
  return code;
1,581✔
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,442✔
4821

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

4827
static uint8_t hllCountNum(void* data, int32_t bytes, int32_t* buk) {
3,663,079✔
4828
  uint64_t hash = MurmurHash3_64(data, bytes);
3,663,079✔
4829
  int32_t  index = hash & HLL_BUCKET_MASK;
3,662,372✔
4830
  hash >>= HLL_BUCKET_BITS;
3,662,372✔
4831
  hash |= ((uint64_t)1 << HLL_DATA_BITS);
3,662,372✔
4832
  uint64_t bit = 1;
3,662,372✔
4833
  uint8_t  count = 1;
3,662,372✔
4834
  while ((hash & bit) == 0) {
7,969,259✔
4835
    count++;
4,306,887✔
4836
    bit <<= 1;
4,306,887✔
4837
  }
4838
  *buk = index;
3,662,372✔
4839
  return count;
3,662,372✔
4840
}
4841

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

4846
  for (int32_t j = 0; j < HLL_BUCKETS >> 3; j++) {
463,529,454✔
4847
    if (*word == 0) {
463,299,761✔
4848
      bucketHisto[0] += 8;
462,297,969✔
4849
    } else {
4850
      bytes = (uint8_t*)word;
1,001,792✔
4851
      bucketHisto[bytes[0]]++;
1,001,792✔
4852
      bucketHisto[bytes[1]]++;
1,001,792✔
4853
      bucketHisto[bytes[2]]++;
1,001,792✔
4854
      bucketHisto[bytes[3]]++;
1,001,792✔
4855
      bucketHisto[bytes[4]]++;
1,001,792✔
4856
      bucketHisto[bytes[5]]++;
1,001,792✔
4857
      bucketHisto[bytes[6]]++;
1,001,792✔
4858
      bucketHisto[bytes[7]]++;
1,001,792✔
4859
    }
4860
    word++;
463,299,761✔
4861
  }
4862
}
229,693✔
4863
static double hllTau(double x) {
229,694✔
4864
  if (x == 0. || x == 1.) return 0.;
229,694!
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) {
229,702✔
4878
  if (x == 1.0) return INFINITY;
229,702✔
4879
  double zPrime;
4880
  double y = 1;
202,263✔
4881
  double z = x;
202,263✔
4882
  do {
4883
    x *= x;
3,955,187✔
4884
    zPrime = z;
3,955,187✔
4885
    z += x * y;
3,955,187✔
4886
    y += y;
3,955,187✔
4887
  } while (zPrime != z);
3,955,187✔
4888
  return z;
202,263✔
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) {
229,672✔
4894
  double  m = HLL_BUCKETS;
229,672✔
4895
  int32_t buckethisto[64] = {0};
229,672✔
4896
  hllBucketHisto(buckets, buckethisto);
229,672✔
4897

4898
  double z = m * hllTau((m - buckethisto[HLL_DATA_BITS + 1]) / (double)m);
229,696✔
4899
  for (int j = HLL_DATA_BITS; j >= 1; --j) {
11,711,247✔
4900
    z += buckethisto[j];
11,481,544✔
4901
    z *= 0.5;
11,481,544✔
4902
  }
4903

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

4907
  return (uint64_t)E;
229,703✔
4908
}
4909

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

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

4916
  int32_t type = pCol->info.type;
252,765✔
4917
  int32_t bytes = pCol->info.bytes;
252,765✔
4918

4919
  int32_t start = pInput->startRowIndex;
252,765✔
4920
  int32_t numOfRows = pInput->numOfRows;
252,765✔
4921

4922
  int32_t numOfElems = 0;
252,765✔
4923
  if (IS_NULL_TYPE(type)) {
252,765✔
4924
    goto _hll_over;
1,544✔
4925
  }
4926

4927
  for (int32_t i = start; i < numOfRows + start; ++i) {
4,806,800✔
4928
    if (pCol->hasNull && colDataIsNull_s(pCol, i)) {
6,205,761!
4929
      continue;
892,197✔
4930
    }
4931

4932
    numOfElems++;
3,663,755✔
4933

4934
    char* data = colDataGetData(pCol, i);
3,663,755!
4935
    if (IS_VAR_DATA_TYPE(type)) {
3,663,755!
4936
      bytes = varDataLen(data);
1,050,491✔
4937
      data = varDataVal(data);
1,050,491✔
4938
    }
4939

4940
    int32_t index = 0;
3,663,755✔
4941
    uint8_t count = hllCountNum(data, bytes, &index);
3,663,755✔
4942
    uint8_t oldcount = pInfo->buckets[index];
3,663,382✔
4943
    if (count > oldcount) {
3,663,382✔
4944
      pInfo->buckets[index] = count;
1,031,969✔
4945
    }
4946
  }
4947

4948
_hll_over:
250,848✔
4949
  pInfo->totalCount += numOfElems;
252,392✔
4950

4951
  if (pInfo->totalCount == 0 && !tsCountAlwaysReturnValue) {
252,392✔
4952
    SET_VAL(GET_RES_INFO(pCtx), 0, 1);
1,851✔
4953
  } else {
4954
    SET_VAL(GET_RES_INFO(pCtx), 1, 1);
250,541✔
4955
  }
4956

4957
  return TSDB_CODE_SUCCESS;
252,392✔
4958
}
4959

4960
static void hllTransferInfo(SHLLInfo* pInput, SHLLInfo* pOutput) {
11,733✔
4961
  for (int32_t k = 0; k < HLL_BUCKETS; ++k) {
188,313,670✔
4962
    if (pOutput->buckets[k] < pInput->buckets[k]) {
188,301,937✔
4963
      pOutput->buckets[k] = pInput->buckets[k];
209,512✔
4964
    }
4965
  }
4966
  pOutput->totalCount += pInput->totalCount;
11,733✔
4967
}
11,733✔
4968

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

4973
  if (IS_NULL_TYPE(pCol->info.type)) {
11,646!
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,646!
4979
    return TSDB_CODE_SUCCESS;
×
4980
  }
4981

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

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

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

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

4999
  return TSDB_CODE_SUCCESS;
11,649✔
5000
}
5001

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

5005
  SHLLInfo* pHllInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
229,671✔
5006
  pHllInfo->result = hllCountCnt(pHllInfo->buckets);
229,671✔
5007
  if (tsCountAlwaysReturnValue && pHllInfo->result == 0) {
229,711✔
5008
    pInfo->numOfRes = 1;
25,611✔
5009
  }
5010

5011
  return functionFinalize(pCtx, pBlock);
229,711✔
5012
}
5013

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

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

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

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

5036
_exit:
11,442✔
5037
  taosMemoryFree(res);
11,442!
5038
  return code;
11,445✔
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,660✔
5055
  pEnv->calcMemSize = sizeof(SStateInfo);
7,660✔
5056
  return true;
7,660✔
5057
}
5058

5059
static int8_t getStateOpType(char* opStr) {
7,877✔
5060
  int8_t opType;
5061
  if (strncasecmp(opStr, "LT", 2) == 0) {
7,877✔
5062
    opType = STATE_OPER_LT;
1,525✔
5063
  } else if (strncasecmp(opStr, "GT", 2) == 0) {
6,352✔
5064
    opType = STATE_OPER_GT;
1,625✔
5065
  } else if (strncasecmp(opStr, "LE", 2) == 0) {
4,727✔
5066
    opType = STATE_OPER_LE;
496✔
5067
  } else if (strncasecmp(opStr, "GE", 2) == 0) {
4,231✔
5068
    opType = STATE_OPER_GE;
1,357✔
5069
  } else if (strncasecmp(opStr, "NE", 2) == 0) {
2,874✔
5070
    opType = STATE_OPER_NE;
2,378✔
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,877✔
5078
}
5079

5080
static bool checkStateOp(int8_t op, SColumnInfoData* pCol, int32_t index, SVariant param) {
387,659✔
5081
  char* data = colDataGetData(pCol, index);
387,659!
5082
  switch (pCol->info.type) {
387,659!
5083
    case TSDB_DATA_TYPE_TINYINT: {
21,048✔
5084
      int8_t v = *(int8_t*)data;
21,048✔
5085
      STATE_COMP(op, v, param);
21,048!
UNCOV
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,056✔
5094
      int16_t v = *(int16_t*)data;
22,056✔
5095
      STATE_COMP(op, v, param);
22,056!
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: {
85,768✔
5104
      int32_t v = *(int32_t*)data;
85,768✔
5105
      STATE_COMP(op, v, param);
85,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: {
64,284✔
5114
      int64_t v = *(int64_t*)data;
64,284✔
5115
      STATE_COMP(op, v, param);
64,284!
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: {
84,056✔
5124
      float v = *(float*)data;
84,056✔
5125
      STATE_COMP(op, v, param);
84,056!
UNCOV
5126
      break;
×
5127
    }
5128
    case TSDB_DATA_TYPE_DOUBLE: {
100,076✔
5129
      double v = *(double*)data;
100,076✔
5130
      STATE_COMP(op, v, param);
100,076!
5131
      break;
1✔
5132
    }
5133
    default: {
×
5134
      return false;
×
5135
    }
5136
  }
5137
  return false;
1✔
5138
}
5139

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

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

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

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

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

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

5165
    pInfo->isPrevTsSet = true;
513,621✔
5166
    numOfElems++;
513,621✔
5167

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

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

5182
    int64_t output = -1;
174,109✔
5183
    if (ret) {
174,109✔
5184
      output = ++pInfo->count;
138,094✔
5185
    } else {
5186
      pInfo->count = 0;
36,015✔
5187
    }
5188
    code = colDataSetVal(pOutput, pCtx->offset + numOfElems - 1, (char*)&output, false);
174,109✔
5189
    if (TSDB_CODE_SUCCESS != code) {
174,109!
5190
      return code;
×
5191
    }
5192

5193
    // handle selectivity
5194
    if (pCtx->subsidiaries.num > 0) {
174,109✔
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,952✔
5203
  return TSDB_CODE_SUCCESS;
2,952✔
5204
}
5205

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

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

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

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

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

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

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

5237
    pInfo->isPrevTsSet = true;
372,793✔
5238
    numOfElems++;
372,793✔
5239

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

5252
    bool    ret = checkStateOp(op, pInputCol, i, pCtx->param[2].param);
214,701✔
5253
    int64_t output = -1;
214,701✔
5254
    if (ret) {
214,701✔
5255
      if (pInfo->durationStart == 0) {
146,266✔
5256
        output = 0;
40,628✔
5257
        pInfo->durationStart = tsList[i];
40,628✔
5258
      } else {
5259
        output = (tsList[i] - pInfo->durationStart) / timeUnit;
105,638✔
5260
      }
5261
    } else {
5262
      pInfo->durationStart = 0;
68,435✔
5263
    }
5264
    code = colDataSetVal(pOutput, pCtx->offset + numOfElems - 1, (char*)&output, false);
214,701✔
5265
    if (TSDB_CODE_SUCCESS != code) {
214,701!
5266
      return code;
×
5267
    }
5268

5269
    // handle selectivity
5270
    if (pCtx->subsidiaries.num > 0) {
214,701✔
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;
4,925✔
5279
  return TSDB_CODE_SUCCESS;
4,925✔
5280
}
5281

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

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

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

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

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

5309
    int32_t pos = startOffset + numOfElems;
856,626✔
5310
    if (colDataIsNull_f(pInputCol->nullbitmap, i)) {
856,626✔
5311
      // colDataSetNULL(pOutput, i);
5312
      continue;
480,111✔
5313
    }
5314

5315
    char* data = colDataGetData(pInputCol, i);
376,515!
5316
    if (IS_SIGNED_NUMERIC_TYPE(type)) {
684,376!
5317
      int64_t v;
5318
      GET_TYPED_DATA(v, int64_t, type, data);
307,839!
5319
      pSumRes->isum += v;
307,839✔
5320
      code = colDataSetVal(pOutput, pos, (char*)&pSumRes->isum, false);
307,839✔
5321
      if (TSDB_CODE_SUCCESS != code) {
307,861!
5322
        return code;
×
5323
      }
5324
    } else if (IS_UNSIGNED_NUMERIC_TYPE(type)) {
69,186!
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)) {
68,166!
5333
      double v;
5334
      GET_TYPED_DATA(v, double, type, data);
68,200!
5335
      pSumRes->dsum += v;
68,200✔
5336
      // check for overflow
5337
      if (isinf(pSumRes->dsum) || isnan(pSumRes->dsum)) {
68,200!
5338
        colDataSetNULL(pOutput, pos);
6!
5339
      } else {
5340
        code = colDataSetVal(pOutput, pos, (char*)&pSumRes->dsum, false);
68,194✔
5341
        if (TSDB_CODE_SUCCESS != code) {
68,194!
5342
          return code;
×
5343
        }
5344
      }
5345
    }
5346

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

5355
    numOfElems++;
376,537✔
5356
  }
5357

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

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

5367
int32_t mavgFunctionSetup(SqlFunctionCtx* pCtx, SResultRowEntryInfo* pResultInfo) {
8,049✔
5368
  if (pResultInfo->initialized) {
8,049✔
5369
    return TSDB_CODE_SUCCESS;
3,636✔
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,415✔
5376
  pInfo->pos = 0;
4,415✔
5377
  pInfo->sum = 0;
4,415✔
5378
  pInfo->prevTs = -1;
4,415✔
5379
  pInfo->isPrevTsSet = false;
4,415✔
5380
  pInfo->numOfPoints = pCtx->param[1].param.i;
4,415✔
5381
  if (pInfo->numOfPoints < 1 || pInfo->numOfPoints > MAVG_MAX_POINTS_NUM) {
4,415!
5382
    return TSDB_CODE_FUNC_FUNTION_PARA_VALUE;
×
5383
  }
5384
  pInfo->pointsMeet = false;
4,416✔
5385

5386
  return TSDB_CODE_SUCCESS;
4,416✔
5387
}
5388

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

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

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

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

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

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

5422
    if (!pInfo->pointsMeet && (pInfo->pos < pInfo->numOfPoints - 1)) {
267,474✔
5423
      pInfo->points[pInfo->pos] = v;
265,679✔
5424
      pInfo->sum += v;
265,679✔
5425
    } else {
5426
      if (!pInfo->pointsMeet && (pInfo->pos == pInfo->numOfPoints - 1)) {
1,795!
5427
        pInfo->sum += v;
544✔
5428
        pInfo->pointsMeet = true;
544✔
5429
      } else {
5430
        pInfo->sum = pInfo->sum + v - pInfo->points[pInfo->pos];
1,251✔
5431
      }
5432

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

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

5453
      numOfElems++;
1,795✔
5454
    }
5455

5456
    pInfo->pos++;
267,474✔
5457
    if (pInfo->pos == pInfo->numOfPoints) {
267,474✔
5458
      pInfo->pos = 0;
897✔
5459
    }
5460
  }
5461

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

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

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

5473
  return pInfo;
24,764✔
5474
}
5475

5476
bool getSampleFuncEnv(SFunctionNode* pFunc, SFuncExecEnv* pEnv) {
5,817✔
5477
  SColumnNode* pCol = (SColumnNode*)nodesListGetNode(pFunc->pParameterList, 0);
5,817✔
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,650✔
5485
  if (pResultInfo->initialized) {
11,650!
5486
    return TSDB_CODE_SUCCESS;
×
5487
  }
5488
  if (TSDB_CODE_SUCCESS != functionSetup(pCtx, pResultInfo)) {
11,650!
5489
    return TSDB_CODE_FUNC_SETUP_ERROR;
×
5490
  }
5491

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

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

5505
  return TSDB_CODE_SUCCESS;
11,650✔
5506
}
5507

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

5512
static int32_t doReservoirSample(SqlFunctionCtx* pCtx, SSampleInfo* pInfo, char* data, int32_t index) {
358,479✔
5513
  pInfo->totalPoints++;
358,479✔
5514
  if (pInfo->numSampled < pInfo->samples) {
358,479✔
5515
    sampleAssignResult(pInfo, data, pInfo->numSampled);
293,641✔
5516
    if (pCtx->subsidiaries.num > 0) {
293,640✔
5517
      int32_t code = saveTupleData(pCtx, index, pCtx->pSrcBlock, &pInfo->tuplePos[pInfo->numSampled]);
6,201✔
5518
      if (code != TSDB_CODE_SUCCESS) {
6,270!
5519
        return code;
×
5520
      }
5521
    }
5522
    pInfo->numSampled++;
293,709✔
5523
  } else {
5524
    int32_t j = taosRand() % (pInfo->totalPoints);
64,838✔
5525
    if (j < pInfo->samples) {
64,905✔
5526
      sampleAssignResult(pInfo, data, j);
24,214✔
5527
      if (pCtx->subsidiaries.num > 0) {
24,214✔
5528
        int32_t code = updateTupleData(pCtx, index, pCtx->pSrcBlock, &pInfo->tuplePos[j]);
354✔
5529
        if (code != TSDB_CODE_SUCCESS) {
366!
5530
          return code;
×
5531
        }
5532
      }
5533
    }
5534
  }
5535

5536
  return TSDB_CODE_SUCCESS;
358,626✔
5537
}
5538

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

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

5545
  SColumnInfoData* pInputCol = pInput->pData[0];
13,114✔
5546
  for (int32_t i = pInput->startRowIndex; i < pInput->numOfRows + pInput->startRowIndex; i += 1) {
891,528✔
5547
    if (colDataIsNull_s(pInputCol, i)) {
1,753,328✔
5548
      continue;
519,874✔
5549
    }
5550

5551
    char*   data = colDataGetData(pInputCol, i);
356,790!
5552
    int32_t code = doReservoirSample(pCtx, pInfo, data, i);
356,790✔
5553
    if (code != TSDB_CODE_SUCCESS) {
358,540!
5554
      return code;
×
5555
    }
5556
  }
5557

5558
  if (pInfo->numSampled == 0 && pCtx->subsidiaries.num > 0 && !pInfo->nullTupleSaved) {
14,864✔
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,864✔
5567
  return TSDB_CODE_SUCCESS;
14,864✔
5568
}
5569

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

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

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

5583
  int32_t currentRow = pBlock->info.rows;
11,650✔
5584
  if (pInfo->numSampled == 0) {
11,650✔
5585
    colDataSetNULL(pCol, currentRow);
2,927✔
5586
    code = setSelectivityValue(pCtx, pBlock, &pInfo->nullTuplePos, currentRow);
2,927✔
5587
    return code;
2,927✔
5588
  }
5589
  for (int32_t i = 0; i < pInfo->numSampled; ++i) {
302,528✔
5590
    code = colDataSetVal(pCol, currentRow + i, pInfo->data + i * pInfo->colBytes, false);
293,812✔
5591
    if (TSDB_CODE_SUCCESS != code) {
294,122!
5592
      return code;
×
5593
    }
5594
    code = setSelectivityValue(pCtx, pBlock, &pInfo->tuplePos[i], currentRow + i);
294,122✔
5595
    if (TSDB_CODE_SUCCESS != code) {
293,805!
5596
      return code;
×
5597
    }
5598
  }
5599

5600
  return code;
8,716✔
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,445✔
5842
  pEnv->calcMemSize = sizeof(SModeInfo);
5,445✔
5843
  return true;
5,445✔
5844
}
5845

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

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

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

5878
static void modeFunctionCleanup(SModeInfo* pInfo) {
5,176✔
5879
  taosHashCleanup(pInfo->pHash);
5,176✔
5880
  pInfo->pHash = NULL;
5,176✔
5881
  taosMemoryFreeClear(pInfo->buf);
5,176!
5882
}
5,176✔
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) {
541,366✔
5892
  if (IS_VAR_DATA_TYPE(pInfo->colType)) {
541,366!
5893
    if (pInfo->colType == TSDB_DATA_TYPE_JSON) {
60,019!
5894
      (void)memcpy(pInfo->buf, data, getJsonValueLen(data));
×
5895
    } else {
5896
      (void)memcpy(pInfo->buf, data, varDataTLen(data));
60,019✔
5897
    }
5898
  } else {
5899
    (void)memcpy(pInfo->buf, data, pInfo->colBytes);
481,347✔
5900
  }
5901

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

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

5918
  SModeItem* pHashItem = (SModeItem*)taosHashGet(pInfo->pHash, data, hashKeyBytes);
583,690✔
5919
  if (pHashItem == NULL) {
580,166✔
5920
    int32_t   size = sizeof(SModeItem);
541,267✔
5921
    SModeItem item = {0};
541,267✔
5922

5923
    item.count += 1;
541,267✔
5924
    code = saveModeTupleData(pCtx, data, pInfo, &item.dataPos);
541,267✔
5925
    if (code != TSDB_CODE_SUCCESS) {
540,466!
5926
      return code;
×
5927
    }
5928

5929
    if (pCtx->subsidiaries.num > 0) {
540,466✔
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));
540,466✔
5937
    if (code != TSDB_CODE_SUCCESS) {
544,944!
5938
      return code;
×
5939
    }
5940
  } else {
5941
    pHashItem->count += 1;
38,899✔
5942
    if (pCtx->subsidiaries.num > 0) {
38,899✔
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;
583,843✔
5951
}
5952

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

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

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

5962
  int32_t numOfElems = 0;
6,209✔
5963
  int32_t startOffset = pCtx->offset;
6,209✔
5964
  for (int32_t i = pInput->startRowIndex; i < pInput->numOfRows + pInput->startRowIndex; ++i) {
932,208✔
5965
    if (colDataIsNull_s(pInputCol, i)) {
1,851,128✔
5966
      continue;
342,786✔
5967
    }
5968
    numOfElems++;
582,778✔
5969

5970
    char*   data = colDataGetData(pInputCol, i);
582,778!
5971
    int32_t code = doModeAdd(pInfo, i, pCtx, data);
582,778✔
5972
    if (code != TSDB_CODE_SUCCESS) {
583,831✔
5973
      modeFunctionCleanup(pInfo);
618✔
5974
      return code;
×
5975
    }
5976
  }
5977

5978
  if (numOfElems == 0 && pCtx->subsidiaries.num > 0 && !pInfo->nullTupleSaved) {
6,644!
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,644✔
5988

5989
  return TSDB_CODE_SUCCESS;
6,644✔
5990
}
5991

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

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

6007
  void* pIter = taosHashIterate(pInfo->pHash, NULL);
5,176✔
6008
  while (pIter != NULL) {
550,661✔
6009
    SModeItem* pItem = (SModeItem*)pIter;
545,485✔
6010
    if (pItem->count >= maxCount) {
545,485✔
6011
      maxCount = pItem->count;
477,307✔
6012
      resDataPos = pItem->dataPos;
477,307✔
6013
      resTuplePos = pItem->tuplePos;
477,307✔
6014
    }
6015

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

6019
  if (maxCount != 0) {
5,176✔
6020
    char* pData = NULL;
3,179✔
6021
    code = loadTupleData(pCtx, &resDataPos, &pData);
3,179✔
6022
    if (pData == NULL || TSDB_CODE_SUCCESS != code) {
3,179!
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,179✔
6031
    if (TSDB_CODE_SUCCESS != code) {
3,179!
6032
      modeFunctionCleanup(pInfo);
×
6033
      return code;
×
6034
    }
6035
    code = setSelectivityValue(pCtx, pBlock, &resTuplePos, currentRow);
3,179✔
6036
  } else {
6037
    colDataSetNULL(pCol, currentRow);
1,997!
6038
    code = setSelectivityValue(pCtx, pBlock, &pInfo->nullTuplePos, currentRow);
1,997✔
6039
  }
6040

6041
  modeFunctionCleanup(pInfo);
5,176✔
6042

6043
  return code;
5,176✔
6044
}
6045

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

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

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

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

6071
  if ((s.val >= 0 && e.val >= 0) || (s.val <= 0 && e.val <= 0)) {
449,298✔
6072
    return (s.val + e.val) * (e.key - s.key) / 2;
378,668✔
6073
  }
6074

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

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

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

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

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

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

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

6114
      pInfo->dOutput += twa_get_area(pCtx->start, *last);
13,611✔
6115
      pInfo->win.skey = pCtx->start.key;
13,611✔
6116
      pInfo->numOfElems++;
13,611✔
6117
      break;
13,611✔
6118
    }
6119
  } else if (pInfo->p.key == INT64_MIN) {
31,531✔
6120
    while (1) {
6121
      code = funcInputGetNextRow(pCtx, &row, &result);
132,709✔
6122
      if (TSDB_CODE_SUCCESS != code) {
132,707!
6123
        return code;
×
6124
      }
6125
      if (!result) {
132,707✔
6126
        break;
13,103✔
6127
      }
6128
      if (row.isDataNull) {
119,604✔
6129
        continue;
101,472✔
6130
      }
6131

6132
      last->key = row.ts;
18,132✔
6133

6134
      GET_TYPED_DATA(last->val, double, pInputCol->info.type, row.pData);
18,132✔
6135

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

6142
  SPoint1 st = {0};
45,142✔
6143

6144
  // calculate the value of
6145
  while (1) {
6146
    code = funcInputGetNextRow(pCtx, &row, &result);
467,442✔
6147
    if (TSDB_CODE_SUCCESS != code) {
467,570!
6148
      return code;
×
6149
    }
6150
    if (!result) {
467,570✔
6151
      break;
45,144✔
6152
    }
6153
    if (row.isDataNull) {
422,426✔
6154
      continue;
378✔
6155
    }
6156
    pInfo->numOfElems++;
422,048✔
6157
    switch (pInputCol->info.type) {
422,048✔
6158
      case TSDB_DATA_TYPE_TINYINT: {
45,046✔
6159
        INIT_INTP_POINT(st, row.ts, *(int8_t*)row.pData);
45,046✔
6160
        break;
45,046✔
6161
      }
6162
      case TSDB_DATA_TYPE_SMALLINT: {
51,730✔
6163
        INIT_INTP_POINT(st, row.ts, *(int16_t*)row.pData);
51,730✔
6164
        break;
51,730✔
6165
      }
6166
      case TSDB_DATA_TYPE_INT: {
76,223✔
6167
        INIT_INTP_POINT(st, row.ts, *(int32_t*)row.pData);
76,223✔
6168
        break;
76,223✔
6169
      }
6170
      case TSDB_DATA_TYPE_BIGINT: {
48,373✔
6171
        INIT_INTP_POINT(st, row.ts, *(int64_t*)row.pData);
48,373✔
6172
        break;
48,373✔
6173
      }
6174
      case TSDB_DATA_TYPE_FLOAT: {
38,491✔
6175
        INIT_INTP_POINT(st, row.ts, *(float_t*)row.pData);
38,491✔
6176
        break;
38,491✔
6177
      }
6178
      case TSDB_DATA_TYPE_DOUBLE: {
49,650✔
6179
        INIT_INTP_POINT(st, row.ts, *(double*)row.pData);
49,650✔
6180
        break;
49,650✔
6181
      }
6182
      case TSDB_DATA_TYPE_UTINYINT: {
29,271✔
6183
        INIT_INTP_POINT(st, row.ts, *(uint8_t*)row.pData);
29,271✔
6184
        break;
29,271✔
6185
      }
6186
      case TSDB_DATA_TYPE_USMALLINT: {
28,860✔
6187
        INIT_INTP_POINT(st, row.ts, *(uint16_t*)row.pData);
28,860✔
6188
        break;
28,860✔
6189
      }
6190
      case TSDB_DATA_TYPE_UINT: {
30,834✔
6191
        INIT_INTP_POINT(st, row.ts, *(uint32_t*)row.pData);
30,834✔
6192
        break;
30,834✔
6193
      }
6194
      case TSDB_DATA_TYPE_UBIGINT: {
23,278✔
6195
        INIT_INTP_POINT(st, row.ts, *(uint64_t*)row.pData);
23,278✔
6196
        break;
23,278✔
6197
      }
6198
      default: {
292✔
6199
        return TSDB_CODE_FUNC_FUNTION_PARA_TYPE;
292✔
6200
      }
6201
    }
6202
    if (pInfo->p.key == st.key) {
421,756!
6203
      return TSDB_CODE_FUNC_DUP_TIMESTAMP;
×
6204
    }
6205

6206
    pInfo->dOutput += twa_get_area(pInfo->p, st);
421,756✔
6207
    pInfo->p = st;
421,922✔
6208
  }
6209

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

6217
  pInfo->win.ekey = pInfo->p.key;
45,144✔
6218

6219
_twa_over:
45,144✔
6220
  SET_VAL(pResInfo, 1, 1);
45,144✔
6221
  return TSDB_CODE_SUCCESS;
45,144✔
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) {
44,860✔
6237
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
44,860✔
6238

6239
  STwaInfo* pInfo = (STwaInfo*)GET_ROWCELL_INTERBUF(pResInfo);
44,860✔
6240
  if (pInfo->numOfElems == 0) {
44,860✔
6241
    pResInfo->numOfRes = 0;
13,005✔
6242
  } else {
6243
    if (pInfo->win.ekey == pInfo->win.skey) {
31,855✔
6244
      pInfo->dTwaRes = pInfo->p.val;
12,923✔
6245
    } else if (pInfo->win.ekey == INT64_MAX || pInfo->win.skey == INT64_MIN) {  // no data in timewindow
18,932!
6246
      pInfo->dTwaRes = 0;
1✔
6247
    } else {
6248
      pInfo->dTwaRes = pInfo->dOutput / (pInfo->win.ekey - pInfo->win.skey);
18,931✔
6249
    }
6250

6251
    pResInfo->numOfRes = 1;
31,855✔
6252
  }
6253

6254
  return functionFinalize(pCtx, pBlock);
44,860✔
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) {
675✔
6615
  pEnv->calcMemSize = sizeof(SDerivInfo);
675✔
6616
  return true;
675✔
6617
}
6618

6619
int32_t derivativeFuncSetup(SqlFunctionCtx* pCtx, SResultRowEntryInfo* pResInfo) {
1,446✔
6620
  if (pResInfo->initialized) {
1,446✔
6621
    return TSDB_CODE_SUCCESS;
669✔
6622
  }
6623
  if (TSDB_CODE_SUCCESS != functionSetup(pCtx, pResInfo)) {
777!
6624
    return TSDB_CODE_FUNC_SETUP_ERROR;
×
6625
  }
6626

6627
  SDerivInfo* pDerivInfo = GET_ROWCELL_INTERBUF(pResInfo);
777✔
6628

6629
  pDerivInfo->ignoreNegative = pCtx->param[2].param.i;
777✔
6630
  pDerivInfo->prevTs = -1;
777✔
6631
  pDerivInfo->tsWindow = pCtx->param[1].param.i;
777✔
6632
  pDerivInfo->valueSet = false;
777✔
6633
  return TSDB_CODE_SUCCESS;
777✔
6634
}
6635

6636
int32_t derivativeFunction(SqlFunctionCtx* pCtx) {
771✔
6637
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
771✔
6638
  SDerivInfo*          pDerivInfo = GET_ROWCELL_INTERBUF(pResInfo);
771✔
6639

6640
  SInputColumnInfoData* pInput = &pCtx->input;
771✔
6641
  SColumnInfoData*      pInputCol = pInput->pData[0];
771✔
6642

6643
  int32_t          numOfElems = 0;
771✔
6644
  SColumnInfoData* pOutput = (SColumnInfoData*)pCtx->pOutput;
771✔
6645
  SColumnInfoData* pTsOutput = pCtx->pTsOutput;
771✔
6646
  int32_t          code = TSDB_CODE_SUCCESS;
771✔
6647

6648
  funcInputUpdate(pCtx);
771✔
6649

6650
  double v = 0;
771✔
6651
  if (pCtx->order == TSDB_ORDER_ASC) {
771✔
6652
    SFuncInputRow row = {0};
723✔
6653
    bool          result = false;
723✔
6654
    while (1) {
73,178✔
6655
      code = funcInputGetNextRow(pCtx, &row, &result);
73,901✔
6656
      if (TSDB_CODE_SUCCESS != code) {
73,901!
6657
        return code;
×
6658
      }
6659
      if (!result) {
73,901✔
6660
        break;
723✔
6661
      }
6662
      if (row.isDataNull) {
73,178✔
6663
        continue;
30,109✔
6664
      }
6665

6666
      char* d = row.pData;
43,069✔
6667
      GET_TYPED_DATA(v, double, pInputCol->info.type, d);
43,069!
6668

6669
      int32_t pos = pCtx->offset + numOfElems;
43,069✔
6670
      if (!pDerivInfo->valueSet) {  // initial value is not set yet
43,069✔
6671
        pDerivInfo->valueSet = true;
412✔
6672
      } else {
6673
        if (row.ts == pDerivInfo->prevTs) {
42,657!
6674
          return TSDB_CODE_FUNC_DUP_TIMESTAMP;
×
6675
        }
6676
        double r = ((v - pDerivInfo->prevValue) * pDerivInfo->tsWindow) / (row.ts - pDerivInfo->prevTs);
42,657✔
6677
        if (pDerivInfo->ignoreNegative && r < 0) {
42,657✔
6678
        } else {
6679
          if (isinf(r) || isnan(r)) {
34,399!
6680
            colDataSetNULL(pOutput, pos);
×
6681
          } else {
6682
            code = colDataSetVal(pOutput, pos, (const char*)&r, false);
34,399✔
6683
            if (code != TSDB_CODE_SUCCESS) {
34,399!
6684
              return code;
×
6685
            }
6686
          }
6687

6688
          if (pTsOutput != NULL) {
34,399!
6689
            colDataSetInt64(pTsOutput, pos, &row.ts);
×
6690
          }
6691

6692
          // handle selectivity
6693
          if (pCtx->subsidiaries.num > 0) {
34,399✔
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++;
34,399✔
6701
        }
6702
      }
6703

6704
      pDerivInfo->prevValue = v;
43,069✔
6705
      pDerivInfo->prevTs = row.ts;
43,069✔
6706
    }
6707
  } else {
6708
    SFuncInputRow row = {0};
48✔
6709
    bool          result = false;
48✔
6710
    while (1) {
684✔
6711
      code = funcInputGetNextRow(pCtx, &row, &result);
732✔
6712
      if (TSDB_CODE_SUCCESS != code) {
732!
6713
        return code;
×
6714
      }
6715
      if (!result) {
732✔
6716
        break;
48✔
6717
      }
6718
      if (row.isDataNull) {
684✔
6719
        continue;
22✔
6720
      }
6721

6722
      char* d = row.pData;
662✔
6723
      GET_TYPED_DATA(v, double, pInputCol->info.type, d);
662!
6724

6725
      int32_t pos = pCtx->offset + numOfElems;
662✔
6726
      if (!pDerivInfo->valueSet) {  // initial value is not set yet
662✔
6727
        pDerivInfo->valueSet = true;
34✔
6728
      } else {
6729
        if (row.ts == pDerivInfo->prevTs) {
628!
6730
          return TSDB_CODE_FUNC_DUP_TIMESTAMP;
×
6731
        }
6732
        double r = ((pDerivInfo->prevValue - v) * pDerivInfo->tsWindow) / (pDerivInfo->prevTs - row.ts);
628✔
6733
        if (pDerivInfo->ignoreNegative && r < 0) {
628✔
6734
        } else {
6735
          if (isinf(r) || isnan(r)) {
620!
6736
            colDataSetNULL(pOutput, pos);
×
6737
          } else {
6738
            code = colDataSetVal(pOutput, pos, (const char*)&r, false);
620✔
6739
            if (code != TSDB_CODE_SUCCESS) {
620!
6740
              return code;
×
6741
            }
6742
          }
6743

6744
          if (pTsOutput != NULL) {
620!
6745
            colDataSetInt64(pTsOutput, pos, &pDerivInfo->prevTs);
×
6746
          }
6747

6748
          // handle selectivity
6749
          if (pCtx->subsidiaries.num > 0) {
620!
6750
            code = appendSelectivityCols(pCtx, row.block, row.rowIndex, pos);
×
6751
            if (code != TSDB_CODE_SUCCESS) {
×
6752
              return code;
×
6753
            }
6754
          }
6755
          numOfElems++;
620✔
6756
        }
6757
      }
6758

6759
      pDerivInfo->prevValue = v;
662✔
6760
      pDerivInfo->prevTs = row.ts;
662✔
6761
    }
6762
  }
6763

6764
  pResInfo->numOfRes = numOfElems;
771✔
6765

6766
  return TSDB_CODE_SUCCESS;
771✔
6767
}
6768

6769
int32_t getIrateInfoSize(int32_t pkBytes) { return (int32_t)sizeof(SRateInfo) + 2 * pkBytes; }
2,485✔
6770

6771
bool getIrateFuncEnv(struct SFunctionNode* pFunc, SFuncExecEnv* pEnv) {
2,231✔
6772
  int32_t pkBytes = (pFunc->hasPk) ? pFunc->pkBytes : 0;
2,231✔
6773
  pEnv->calcMemSize = getIrateInfoSize(pkBytes);
2,231✔
6774
  return true;
2,237✔
6775
}
6776

6777
int32_t irateFuncSetup(SqlFunctionCtx* pCtx, SResultRowEntryInfo* pResInfo) {
24,479✔
6778
  if (pResInfo->initialized) {
24,479!
6779
    return TSDB_CODE_SUCCESS;
×
6780
  }
6781
  if (TSDB_CODE_SUCCESS != functionSetup(pCtx, pResInfo)) {
24,479!
6782
    return TSDB_CODE_FUNC_SETUP_ERROR;
×
6783
  }
6784

6785
  SRateInfo* pInfo = GET_ROWCELL_INTERBUF(pResInfo);
24,479✔
6786

6787
  pInfo->firstKey = INT64_MIN;
24,479✔
6788
  pInfo->lastKey = INT64_MIN;
24,479✔
6789
  pInfo->firstValue = (double)INT64_MIN;
24,479✔
6790
  pInfo->lastValue = (double)INT64_MIN;
24,479✔
6791

6792
  pInfo->hasResult = 0;
24,479✔
6793
  return TSDB_CODE_SUCCESS;
24,479✔
6794
}
6795

6796
static void doSaveRateInfo(SRateInfo* pRateInfo, bool isFirst, int64_t ts, char* pk, double v) {
262,251✔
6797
  if (isFirst) {
262,251✔
6798
    pRateInfo->firstValue = v;
125,192✔
6799
    pRateInfo->firstKey = ts;
125,192✔
6800
    if (pRateInfo->firstPk) {
125,192✔
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;
137,059✔
6815
    pRateInfo->lastKey = ts;
137,059✔
6816
    if (pRateInfo->lastPk) {
137,059✔
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
}
262,251✔
6831

6832
static void initializeRateInfo(SqlFunctionCtx* pCtx, SRateInfo* pRateInfo, bool isMerge) {
25,380✔
6833
  if (pCtx->hasPrimaryKey) {
25,380✔
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;
25,361✔
6845
    pRateInfo->lastPk = NULL;
25,361✔
6846
  }
6847
}
25,380✔
6848

6849
int32_t irateFunction(SqlFunctionCtx* pCtx) {
25,006✔
6850
  int32_t              code = TSDB_CODE_SUCCESS;
25,006✔
6851
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
25,006✔
6852
  SRateInfo*           pRateInfo = GET_ROWCELL_INTERBUF(pResInfo);
25,006✔
6853

6854
  SInputColumnInfoData* pInput = &pCtx->input;
25,006✔
6855
  SColumnInfoData*      pInputCol = pInput->pData[0];
25,006✔
6856

6857
  SColumnInfoData* pOutput = (SColumnInfoData*)pCtx->pOutput;
25,006✔
6858

6859
  funcInputUpdate(pCtx);
25,006✔
6860

6861
  initializeRateInfo(pCtx, pRateInfo, false);
25,008✔
6862

6863
  int32_t       numOfElems = 0;
25,008✔
6864
  int32_t       type = pInputCol->info.type;
25,008✔
6865
  SFuncInputRow row = {0};
25,008✔
6866
  bool          result = false;
25,008✔
6867
  while (1) {
272,047✔
6868
    code = funcInputGetNextRow(pCtx, &row, &result);
297,055✔
6869
    if (TSDB_CODE_SUCCESS != code) {
297,053!
6870
      return code;
×
6871
    }
6872
    if (!result) {
297,053✔
6873
      break;
25,009✔
6874
    }
6875
    if (row.isDataNull) {
272,044✔
6876
      continue;
132,180✔
6877
    }
6878

6879
    char*  data = row.pData;
139,864✔
6880
    double v = 0;
139,864✔
6881
    GET_TYPED_DATA(v, double, type, data);
139,864!
6882

6883
    if (INT64_MIN == pRateInfo->lastKey) {
139,864✔
6884
      doSaveRateInfo(pRateInfo, false, row.ts, row.pPk, v);
11,941✔
6885
      pRateInfo->hasResult = 1;
11,941✔
6886
      continue;
11,941✔
6887
    }
6888

6889
    if (row.ts > pRateInfo->lastKey) {
127,923✔
6890
      if ((INT64_MIN == pRateInfo->firstKey) || pRateInfo->lastKey > pRateInfo->firstKey) {
124,950!
6891
        doSaveRateInfo(pRateInfo, true, pRateInfo->lastKey, pRateInfo->lastPk, pRateInfo->lastValue);
124,950✔
6892
      }
6893
      doSaveRateInfo(pRateInfo, false, row.ts, row.pPk, v);
124,948✔
6894
      continue;
124,945✔
6895
    } else if (row.ts == pRateInfo->lastKey) {
2,973!
6896
      return TSDB_CODE_FUNC_DUP_TIMESTAMP;
×
6897
    }
6898

6899
    if ((INT64_MIN == pRateInfo->firstKey) || row.ts > pRateInfo->firstKey) {
2,973!
6900
      doSaveRateInfo(pRateInfo, true, row.ts, row.pPk, v);
13✔
6901
    } else if (row.ts == pRateInfo->firstKey) {
2,960!
6902
      return TSDB_CODE_FUNC_DUP_TIMESTAMP;
×
6903
    }
6904
  }
6905

6906
  numOfElems++;
25,009✔
6907

6908
  SET_VAL(pResInfo, numOfElems, 1);
25,009!
6909
  return TSDB_CODE_SUCCESS;
25,009✔
6910
}
6911

6912
static double doCalcRate(const SRateInfo* pRateInfo, double tickPerSec) {
24,293✔
6913
  if ((INT64_MIN == pRateInfo->lastKey) || (INT64_MIN == pRateInfo->firstKey) ||
24,293✔
6914
      (pRateInfo->firstKey >= pRateInfo->lastKey)) {
1,080!
6915
    return 0.0;
23,213✔
6916
  }
6917

6918
  double diff = 0;
1,080✔
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,080✔
6922
  if (diff >= pRateInfo->firstValue) {
1,080✔
6923
    diff -= pRateInfo->firstValue;
480✔
6924
  }
6925

6926
  int64_t duration = pRateInfo->lastKey - pRateInfo->firstKey;
1,080✔
6927
  if (duration == 0) {
1,080!
6928
    return 0;
×
6929
  }
6930

6931
  return (duration > 0) ? ((double)diff) / (duration / tickPerSec) : 0.0;
1,080!
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);
115✔
6937
    if (isFirstKey) {
115✔
6938
      doSaveRateInfo(pOutput, false, pInput->firstKey, pInput->firstPk, pInput->firstValue);
53✔
6939
    } else {
6940
      doSaveRateInfo(pOutput, false, pInput->lastKey, pInput->lastPk, pInput->lastValue);
62✔
6941
    }
6942
  } else if ((inputKey < pOutput->lastKey) && (inputKey > pOutput->firstKey)) {
59!
6943
    if (isFirstKey) {
18✔
6944
      doSaveRateInfo(pOutput, true, pInput->firstKey, pInput->firstPk, pInput->firstValue);
9✔
6945
    } else {
6946
      doSaveRateInfo(pOutput, true, pInput->lastKey, pInput->lastPk, pInput->lastValue);
9✔
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) {
24,293✔
7039
  int32_t          slotId = pCtx->pExpr->base.resSchema.slotId;
24,293✔
7040
  SColumnInfoData* pCol = taosArrayGet(pBlock->pDataBlock, slotId);
24,293✔
7041
  if (NULL == pCol) {
24,293!
7042
    return TSDB_CODE_OUT_OF_RANGE;
×
7043
  }
7044

7045
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
24,293✔
7046
  pResInfo->isNullRes = (pResInfo->numOfRes == 0) ? 1 : 0;
24,293✔
7047

7048
  SRateInfo* pInfo = GET_ROWCELL_INTERBUF(pResInfo);
24,293✔
7049
  double     result = doCalcRate(pInfo, (double)TSDB_TICK_PER_SECOND(pCtx->param[1].param.i));
24,293!
7050
  int32_t    code = colDataSetVal(pCol, pBlock->info.rows, (const char*)&result, pResInfo->isNullRes);
24,293✔
7051

7052
  return code;
24,293✔
7053
}
7054

7055
int32_t groupConstValueFunction(SqlFunctionCtx* pCtx) {
81,094,976✔
7056
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
81,094,976✔
7057
  SGroupKeyInfo*       pInfo = GET_ROWCELL_INTERBUF(pResInfo);
81,094,976✔
7058

7059
  SInputColumnInfoData* pInput = &pCtx->input;
81,094,976✔
7060
  SColumnInfoData*      pInputCol = pInput->pData[0];
81,094,976✔
7061

7062
  int32_t startIndex = pInput->startRowIndex;
81,094,976✔
7063

7064
  // escape rest of data blocks to avoid first entry to be overwritten.
7065
  if (pInfo->hasResult) {
81,094,976✔
7066
    goto _group_value_over;
10,532,044✔
7067
  }
7068

7069
  if (pInputCol->pData == NULL || colDataIsNull_s(pInputCol, startIndex)) {
140,892,388✔
7070
    pInfo->isNull = true;
1,607,824✔
7071
    pInfo->hasResult = true;
1,607,824✔
7072
    goto _group_value_over;
1,607,824✔
7073
  }
7074

7075
  char* data = colDataGetData(pInputCol, startIndex);
68,955,108!
7076
  if (IS_VAR_DATA_TYPE(pInputCol->info.type)) {
68,955,108!
7077
    (void)memcpy(pInfo->data, data,
49,521,649✔
7078
                 (pInputCol->info.type == TSDB_DATA_TYPE_JSON) ? getJsonValueLen(data) : varDataTLen(data));
49,521,649✔
7079
  } else {
7080
    (void)memcpy(pInfo->data, data, pInputCol->info.bytes);
19,433,459✔
7081
  }
7082
  pInfo->hasResult = true;
68,955,108✔
7083

7084
_group_value_over:
81,094,976✔
7085

7086
  SET_VAL(pResInfo, 1, 1);
81,094,976✔
7087
  return TSDB_CODE_SUCCESS;
81,094,976✔
7088
}
7089

7090
int32_t groupKeyFunction(SqlFunctionCtx* pCtx) { return groupConstValueFunction(pCtx); }
81,107,147✔
7091

7092
int32_t groupConstValueFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
69,264,034✔
7093
  int32_t          slotId = pCtx->pExpr->base.resSchema.slotId;
69,264,034✔
7094
  int32_t          code = TSDB_CODE_SUCCESS;
69,264,034✔
7095
  SColumnInfoData* pCol = taosArrayGet(pBlock->pDataBlock, slotId);
69,264,034✔
7096
  if (NULL == pCol) {
69,289,473!
7097
    return TSDB_CODE_OUT_OF_RANGE;
×
7098
  }
7099

7100
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
69,289,473✔
7101

7102
  SGroupKeyInfo* pInfo = GET_ROWCELL_INTERBUF(pResInfo);
69,289,473✔
7103

7104
  if (pInfo->hasResult) {
69,289,473!
7105
    int32_t currentRow = pBlock->info.rows;
69,321,107✔
7106
    for (; currentRow < pBlock->info.rows + pResInfo->numOfRes; ++currentRow) {
139,117,352✔
7107
      code = colDataSetVal(pCol, currentRow, pInfo->data, pInfo->isNull ? true : false);
69,301,300✔
7108
      if (TSDB_CODE_SUCCESS != code) {
69,796,245!
7109
        return code;
×
7110
      }
7111
    }
7112
  } else {
7113
    pResInfo->numOfRes = 0;
×
7114
  }
7115

7116
  return code;
69,784,418✔
7117
}
7118

7119
int32_t groupKeyFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) { return groupConstValueFinalize(pCtx, pBlock); }
69,256,343✔
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,385✔
7156
  int32_t numOfElems = 0;
2,385✔
7157

7158
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
2,385✔
7159
  SFirstLastRes*       pInfo = GET_ROWCELL_INTERBUF(pResInfo);
2,385✔
7160

7161
  SInputColumnInfoData* pInput = &pCtx->input;
2,385✔
7162
  SColumnInfoData*      pInputCol = pInput->pData[0];
2,385✔
7163

7164
  int32_t bytes = pInputCol->info.bytes;
2,385✔
7165
  pInfo->bytes = bytes;
2,385✔
7166

7167
  SColumnInfoData* pkCol = pInput->pPrimaryKey;
2,385✔
7168
  pInfo->pkType = -1;
2,385✔
7169
  __compar_fn_t pkCompareFn = NULL;
2,385✔
7170
  if (pCtx->hasPrimaryKey) {
2,385✔
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,781✔
7179
    numOfElems++;
2,395✔
7180

7181
    bool  isNull = colDataIsNull(pInputCol, pInput->numOfRows, i, NULL);
2,395✔
7182
    char* data = isNull ? NULL : colDataGetData(pInputCol, i);
2,395!
7183

7184
    TSKEY cts = getRowPTs(pInput->pPTS, i);
2,395!
7185
    if (pResInfo->numOfRes == 0 || pInfo->ts < cts) {
2,395✔
7186
      int32_t code = doSaveLastrow(pCtx, data, i, cts, pInfo);
2,052✔
7187
      if (code != TSDB_CODE_SUCCESS) {
2,053!
7188
        return code;
×
7189
      }
7190
      pResInfo->numOfRes = 1;
2,053✔
7191
    }
7192
  }
7193

7194
  SET_VAL(pResInfo, numOfElems, 1);
2,386!
7195
  return TSDB_CODE_SUCCESS;
2,386✔
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