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

taosdata / TDengine / #3558

17 Dec 2024 06:05AM UTC coverage: 59.778% (+1.6%) from 58.204%
#3558

push

travis-ci

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

merge: form main to 3.0 branch

132787 of 287595 branches covered (46.17%)

Branch coverage included in aggregate %.

104 of 191 new or added lines in 5 files covered. (54.45%)

6085 existing lines in 168 files now uncovered.

209348 of 284746 relevant lines covered (73.52%)

8164844.48 hits per line

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

71.75
/source/libs/function/src/builtinsimpl.c
1
/*
2
 * Copyright (c) 2019 TAOS Data, Inc. <jhtao@taosdata.com>
3
 *
4
 * This program is free software: you can use, redistribute, and/or modify
5
 * it under the terms of the GNU Affero General Public License, version 3
6
 * or later ("AGPL"), as published by the Free Software Foundation.
7
 *
8
 * This program is distributed in the hope that it will be useful, but WITHOUT
9
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
10
 * FITNESS FOR A PARTICULAR PURPOSE.
11
 *
12
 * You should have received a copy of the GNU Affero General Public License
13
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
14
 */
15

16
#include "builtinsimpl.h"
17
#include "cJSON.h"
18
#include "function.h"
19
#include "functionResInfoInt.h"
20
#include "query.h"
21
#include "querynodes.h"
22
#include "tanalytics.h"
23
#include "tcompare.h"
24
#include "tdatablock.h"
25
#include "tdigest.h"
26
#include "tfunctionInt.h"
27
#include "tglobal.h"
28
#include "thistogram.h"
29
#include "tpercentile.h"
30

31
bool ignoreNegative(int8_t ignoreOption) { return (ignoreOption & 0x1) == 0x1; }
19,833,957✔
32
bool ignoreNull(int8_t ignoreOption) { return (ignoreOption & 0x2) == 0x2; }
223,628✔
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) {
290,529✔
194
  SFuncInputRowIter* pIter = &pCtx->rowIter;
290,529✔
195

196
  if (!pCtx->bInputFinished) {
290,529!
197
    pIter->pInput = &pCtx->input;
290,531✔
198
    pIter->tsList = (TSKEY*)pIter->pInput->pPTS->pData;
290,531✔
199
    pIter->pDataCol = pIter->pInput->pData[0];
290,531✔
200
    pIter->pPkCol = pIter->pInput->pPrimaryKey;
290,531✔
201
    pIter->rowIndex = pIter->pInput->startRowIndex;
290,531✔
202
    pIter->inputEndIndex = pIter->rowIndex + pIter->pInput->numOfRows - 1;
290,531✔
203
    pIter->pSrcBlock = pCtx->pSrcBlock;
290,531✔
204
    if (!pIter->hasGroupId || pIter->groupId != pIter->pSrcBlock->info.id.groupId) {
290,531✔
205
      pIter->hasGroupId = true;
42,991✔
206
      pIter->groupId = pIter->pSrcBlock->info.id.groupId;
42,991✔
207
      pIter->hasPrev = false;
42,991✔
208
    }
209
  } else {
210
    pIter->finalRow = true;
×
211
  }
212
}
290,529✔
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) {
162✔
329
  int32_t idx = rowIndex + 1;
162✔
330
  while (idx <= pIter->inputEndIndex && pIter->tsList[idx] == pIter->tsList[rowIndex]) {
364!
331
    ++idx;
202✔
332
  }
333
  pIter->rowIndex = idx;
162✔
334
}
162✔
335

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

346
bool funcInputGetNextRowAscPk(SFuncInputRowIter* pIter, SFuncInputRow* pRow) {
332✔
347
  if (pIter->hasPrev) {
332!
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) {
332✔
364
      setInputRowInfo(pRow, pIter, pIter->rowIndex, true);
250✔
365

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

382
bool funcInputGetNextRowNoPk(SFuncInputRowIter* pIter, SFuncInputRow* pRow) {
17,419,920✔
383
  if (pIter->rowIndex <= pIter->inputEndIndex) {
17,419,920✔
384
    setInputRowInfo(pRow, pIter, pIter->rowIndex, false);
17,118,893✔
385
    ++pIter->rowIndex;
17,120,083✔
386
    return true;
17,120,083✔
387
  } else {
388
    return false;
301,027✔
389
  }
390
}
391

392
int32_t funcInputGetNextRow(SqlFunctionCtx* pCtx, SFuncInputRow* pRow, bool* res) {
17,420,202✔
393
  SFuncInputRowIter* pIter = &pCtx->rowIter;
17,420,202✔
394
  if (pCtx->hasPrimaryKey) {
17,420,202✔
395
    if (pCtx->order == TSDB_ORDER_ASC) {
332!
396
      *res = funcInputGetNextRowAscPk(pIter, pRow);
332✔
397
      return TSDB_CODE_SUCCESS;
332✔
398
    } else {
399
      return funcInputGetNextRowDescPk(pIter, pRow, res);
×
400
    }
401
  } else {
402
    *res = funcInputGetNextRowNoPk(pIter, pRow);
17,419,870✔
403
    return TSDB_CODE_SUCCESS;
17,420,571✔
404
  }
405
  return TSDB_CODE_SUCCESS;
406
}
407

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

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

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

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

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

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

432
    SColumnInfoData* pDstCol = taosArrayGet(pCtx->pDstBlock->pDataBlock, dstSlotId);
31,122,079✔
433
    if (NULL == pDstCol) {
31,122,079!
434
      return TSDB_CODE_OUT_OF_RANGE;
×
435
    }
436
    if (colDataIsNull_s(pSrcCol, rowIndex) == true) {
62,244,158✔
437
      colDataSetNULL(pDstCol, pos);
1,548,060✔
438
    } else {
439
      int32_t code = colDataSetVal(pDstCol, pos, pData, false);
29,574,019✔
440
      if (TSDB_CODE_SUCCESS != code) {
29,574,019!
441
        return code;
×
442
      }
443
    }
444
  }
445
  return TSDB_CODE_SUCCESS;
15,702,939✔
446
}
447

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

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

453
int32_t functionSetup(SqlFunctionCtx* pCtx, SResultRowEntryInfo* pResultInfo) {
275,116,857✔
454
  if (pResultInfo->initialized) {
275,116,857✔
455
    return TSDB_CODE_SUCCESS;  // already initialized
12,433✔
456
  }
457

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

462
  initResultRowEntry(pResultInfo, pCtx->resDataInfo.interBufSize);
275,104,424✔
463
  return TSDB_CODE_SUCCESS;
275,104,424✔
464
}
465

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

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

479
  return code;
121,228,768✔
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) {
172,634✔
513
  SNode* pParam = nodesListGetNode(pFunc->pParameterList, 0);
172,634✔
514
  if (QUERY_NODE_COLUMN == nodeType(pParam) && PRIMARYKEY_TIMESTAMP_COL_ID == ((SColumnNode*)pParam)->colId) {
172,651!
515
    return FUNC_DATA_REQUIRED_NOT_LOAD;
126,493✔
516
  }
517
  return FUNC_DATA_REQUIRED_SMA_LOAD;
46,158✔
518
}
519

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

525
static int64_t getNumOfElems(SqlFunctionCtx* pCtx) {
95,820,842✔
526
  int64_t numOfElem = 0;
95,820,842✔
527

528
  /*
529
   * 1. column data missing (schema modified) causes pInputCol->hasNull == true. pInput->colDataSMAIsSet == true;
530
   * 2. for general non-primary key columns, pInputCol->hasNull may be true or false, pInput->colDataSMAIsSet == true;
531
   * 3. for primary key column, pInputCol->hasNull always be false, pInput->colDataSMAIsSet == false;
532
   */
533
  SInputColumnInfoData* pInput = &pCtx->input;
95,820,842✔
534
  SColumnInfoData*      pInputCol = pInput->pData[0];
95,820,842✔
535
  if (1 == pInput->numOfRows && pInput->blankFill) {
95,820,842✔
536
    return 0;
427,358✔
537
  }
538
  if (pInput->colDataSMAIsSet && pInput->totalRows == pInput->numOfRows) {
95,393,484✔
539
    numOfElem = pInput->numOfRows - pInput->pColumnDataAgg[0]->numOfNull;
3,531✔
540
  } else {
541
    if (pInputCol->hasNull) {
95,389,953✔
542
      for (int32_t i = pInput->startRowIndex; i < pInput->startRowIndex + pInput->numOfRows; ++i) {
223,520,071✔
543
        if (colDataIsNull(pInputCol, pInput->totalRows, i, NULL)) {
396,655,518!
544
          continue;
1,911,271✔
545
        }
546
        numOfElem += 1;
196,416,488✔
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;
70,197,641✔
552
    }
553
  }
554
  return numOfElem;
95,393,484✔
555
}
556

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

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

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

569
  char* buf = GET_ROWCELL_INTERBUF(pResInfo);
95,981,829✔
570
  if (IS_NULL_TYPE(type)) {
95,981,829✔
571
    // select count(NULL) returns 0
572
    numOfElem = 1;
112,288✔
573
    *((int64_t*)buf) += 0;
112,288✔
574
  } else {
575
    numOfElem = getNumOfElems(pCtx);
95,869,541✔
576
    *((int64_t*)buf) += numOfElem;
95,534,264✔
577
  }
578

579
  if (tsCountAlwaysReturnValue) {
95,646,552!
580
    pResInfo->numOfRes = 1;
95,676,693✔
581
  } else {
582
    SET_VAL(pResInfo, *((int64_t*)buf), 1);
×
583
  }
584

585
  return TSDB_CODE_SUCCESS;
95,646,552✔
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,585,238✔
614
  int32_t numOfElem = 0;
73,585,238✔
615

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

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

624
  if (IS_NULL_TYPE(type)) {
73,585,238✔
625
    numOfElem = 0;
194✔
626
    goto _sum_over;
194✔
627
  }
628

629
  if (pInput->colDataSMAIsSet) {
73,585,044✔
630
    numOfElem = pInput->numOfRows - pAgg->numOfNull;
452✔
631

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

642
    int32_t start = pInput->startRowIndex;
73,584,592✔
643
    int32_t numOfRows = pInput->numOfRows;
73,584,592✔
644

645
    if (IS_SIGNED_NUMERIC_TYPE(type) || type == TSDB_DATA_TYPE_BOOL) {
73,584,592!
646
      if (type == TSDB_DATA_TYPE_TINYINT || type == TSDB_DATA_TYPE_BOOL) {
72,742,399!
647
        LIST_ADD_N(pSumRes->isum, pCol, start, numOfRows, int8_t, numOfElem);
1,432,643✔
648
      } else if (type == TSDB_DATA_TYPE_SMALLINT) {
72,419,662✔
649
        LIST_ADD_N(pSumRes->isum, pCol, start, numOfRows, int16_t, numOfElem);
242,736✔
650
      } else if (type == TSDB_DATA_TYPE_INT) {
72,375,329✔
651
        LIST_ADD_N(pSumRes->isum, pCol, start, numOfRows, int32_t, numOfElem);
269,086,756✔
652
      } else if (type == TSDB_DATA_TYPE_BIGINT) {
17,585,677!
653
        LIST_ADD_N(pSumRes->isum, pCol, start, numOfRows, int64_t, numOfElem);
67,531,226✔
654
      }
655
    } else if (IS_UNSIGNED_NUMERIC_TYPE(type)) {
842,193!
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) {
842,111✔
666
      LIST_ADD_N(pSumRes->dsum, pCol, start, numOfRows, double, numOfElem);
1,979,868✔
667
    } else if (type == TSDB_DATA_TYPE_FLOAT) {
758,830✔
668
      LIST_ADD_N(pSumRes->dsum, pCol, start, numOfRows, float, numOfElem);
1,814,382✔
669
    }
670
  }
671

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

677
_sum_over:
73,848,387✔
678
  if (numOfElem == 0) {
73,585,238✔
679
    if (tsCountAlwaysReturnValue && pCtx->pExpr->pExpr->_function.pFunctNode->hasOriginalFunc &&
94,711✔
680
        fmIsCountLikeFunc(pCtx->pExpr->pExpr->_function.pFunctNode->originalFuncId)) {
11,349✔
681
      numOfElem = 1;
15✔
682
    }
683
  }
684
  // data in the check operation are all null, not output
685
  SET_VAL(GET_RES_INFO(pCtx), numOfElem, 1);
73,585,238✔
686
  return TSDB_CODE_SUCCESS;
73,585,238✔
687
}
688

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

811
int32_t maxFunction(SqlFunctionCtx* pCtx) {
20,409,265✔
812
  int32_t numOfElems = 0;
20,409,265✔
813
  int32_t code = doMinMaxHelper(pCtx, 0, &numOfElems);
20,409,265✔
814
  if (code != TSDB_CODE_SUCCESS) {
20,523,972!
815
    return code;
×
816
  }
817
  SET_VAL(GET_RES_INFO(pCtx), numOfElems, 1);
20,523,972✔
818
  return TSDB_CODE_SUCCESS;
20,523,972✔
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,002,687✔
826
  int32_t code = TSDB_CODE_SUCCESS;
34,002,687✔
827

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

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

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

840
  // NOTE: do nothing change it, for performance issue
841
  if (!pEntryInfo->isNullRes) {
34,011,999✔
842
    switch (pCol->info.type) {
28,435,827!
843
      case TSDB_DATA_TYPE_UBIGINT:
10,975,527✔
844
      case TSDB_DATA_TYPE_BIGINT:
845
        ((int64_t*)pCol->pData)[currentRow] = pRes->v;
10,975,527✔
846
        break;
10,975,527✔
847
      case TSDB_DATA_TYPE_UINT:
16,863,790✔
848
      case TSDB_DATA_TYPE_INT:
849
        colDataSetInt32(pCol, currentRow, (int32_t*)&pRes->v);
16,863,790✔
850
        break;
16,863,790✔
851
      case TSDB_DATA_TYPE_USMALLINT:
211,095✔
852
      case TSDB_DATA_TYPE_SMALLINT:
853
        colDataSetInt16(pCol, currentRow, (int16_t*)&pRes->v);
211,095✔
854
        break;
211,095✔
855
      case TSDB_DATA_TYPE_BOOL:
202,134✔
856
      case TSDB_DATA_TYPE_UTINYINT:
857
      case TSDB_DATA_TYPE_TINYINT:
858
        colDataSetInt8(pCol, currentRow, (int8_t*)&pRes->v);
202,134✔
859
        break;
202,134✔
860
      case TSDB_DATA_TYPE_DOUBLE:
210,816✔
861
        colDataSetDouble(pCol, currentRow, (double*)&pRes->v);
210,816✔
862
        break;
210,816✔
863
      case TSDB_DATA_TYPE_FLOAT: {
2,467✔
864
        float v = GET_FLOAT_VAL(&pRes->v);
2,467✔
865
        colDataSetFloat(pCol, currentRow, &v);
2,467✔
866
        break;
2,467✔
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);
5,576,172!
880
  }
881

882
  taosMemoryFreeClear(pRes->str);
34,011,999!
883
  if (pCtx->subsidiaries.num > 0) {
34,011,999✔
884
    if (pEntryInfo->numOfRes > 0) {
78,517✔
885
      code = setSelectivityValue(pCtx, pBlock, &pRes->tuplePos, currentRow);
76,391✔
886
    } else {
887
      code = setSelectivityValue(pCtx, pBlock, &pRes->nullTuplePos, currentRow);
2,126✔
888
    }
889
  }
890

891
  return code;
34,018,780✔
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,698,779✔
913
  if (pCtx->subsidiaries.num <= 0) {
34,698,779✔
914
    return TSDB_CODE_SUCCESS;
34,562,888✔
915
  }
916

917
  if ((pCtx->saveHandle.pBuf != NULL && pTuplePos->pageId != -1) ||
135,891!
918
      (pCtx->saveHandle.pState && pTuplePos->streamTupleKey.ts > 0)) {
59,622!
919
    int32_t numOfCols = pCtx->subsidiaries.num;
135,892✔
920
    char*   p = NULL;
135,892✔
921
    int32_t code = loadTupleData(pCtx, pTuplePos, &p);
135,892✔
922
    if (p == NULL || TSDB_CODE_SUCCESS != code) {
139,207!
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;
139,207✔
929
    char* pStart = (char*)(nullList + numOfCols * sizeof(bool));
139,207✔
930

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

936
      // group_key function has its own process function
937
      // do not process there
938
      if (fmIsGroupKeyFunc(pc->functionId)) {
163,782✔
939
        continue;
23,430✔
940
      }
941

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

958
  return TSDB_CODE_SUCCESS;
139,213✔
959
}
960

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

1110
  int32_t start = pInput->startRowIndex;
332,088✔
1111
  int32_t numOfRows = pInput->numOfRows;
332,088✔
1112

1113
  if (IS_NULL_TYPE(type)) {
332,088✔
1114
    numOfElem = 0;
139✔
1115
    goto _stddev_over;
139✔
1116
  }
1117

1118
  switch (type) {
331,949!
1119
    case TSDB_DATA_TYPE_TINYINT: {
15,916✔
1120
      int8_t* plist = (int8_t*)pCol->pData;
15,916✔
1121
      for (int32_t i = start; i < numOfRows + start; ++i) {
211,682✔
1122
        if (pCol->hasNull && colDataIsNull_f(pCol->nullbitmap, i)) {
195,766✔
1123
          continue;
23,493✔
1124
        }
1125

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

1132
      break;
15,916✔
1133
    }
1134

1135
    case TSDB_DATA_TYPE_SMALLINT: {
214,545✔
1136
      int16_t* plist = (int16_t*)pCol->pData;
214,545✔
1137
      for (int32_t i = start; i < numOfRows + pInput->startRowIndex; ++i) {
648,471✔
1138
        if (pCol->hasNull && colDataIsNull_f(pCol->nullbitmap, i)) {
433,926✔
1139
          continue;
46,130✔
1140
        }
1141

1142
        numOfElem += 1;
387,796✔
1143
        pStdRes->count += 1;
387,796✔
1144
        pStdRes->isum += plist[i];
387,796✔
1145
        pStdRes->quadraticISum += plist[i] * plist[i];
387,796✔
1146
      }
1147
      break;
214,545✔
1148
    }
1149

1150
    case TSDB_DATA_TYPE_INT: {
18,668✔
1151
      int32_t* plist = (int32_t*)pCol->pData;
18,668✔
1152
      for (int32_t i = start; i < numOfRows + pInput->startRowIndex; ++i) {
295,991✔
1153
        if (pCol->hasNull && colDataIsNull_f(pCol->nullbitmap, i)) {
277,323✔
1154
          continue;
22,906✔
1155
        }
1156

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

1163
      break;
18,668✔
1164
    }
1165

1166
    case TSDB_DATA_TYPE_BIGINT: {
23,554✔
1167
      int64_t* plist = (int64_t*)pCol->pData;
23,554✔
1168
      for (int32_t i = start; i < numOfRows + pInput->startRowIndex; ++i) {
679,640✔
1169
        if (pCol->hasNull && colDataIsNull_f(pCol->nullbitmap, i)) {
656,086✔
1170
          continue;
23,719✔
1171
        }
1172

1173
        numOfElem += 1;
632,367✔
1174
        pStdRes->count += 1;
632,367✔
1175
        pStdRes->isum += plist[i];
632,367✔
1176
        pStdRes->quadraticISum += plist[i] * plist[i];
632,367✔
1177
      }
1178
      break;
23,554✔
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: {
16,422✔
1244
      float* plist = (float*)pCol->pData;
16,422✔
1245
      for (int32_t i = start; i < numOfRows + pInput->startRowIndex; ++i) {
795,926✔
1246
        if (pCol->hasNull && colDataIsNull_f(pCol->nullbitmap, i)) {
779,504✔
1247
          continue;
168,069✔
1248
        }
1249

1250
        numOfElem += 1;
611,435✔
1251
        pStdRes->count += 1;
611,435✔
1252
        pStdRes->dsum += plist[i];
611,435✔
1253
        pStdRes->quadraticDSum += plist[i] * plist[i];
611,435✔
1254
      }
1255
      break;
16,422✔
1256
    }
1257

1258
    case TSDB_DATA_TYPE_DOUBLE: {
42,856✔
1259
      double* plist = (double*)pCol->pData;
42,856✔
1260
      for (int32_t i = start; i < numOfRows + pInput->startRowIndex; ++i) {
1,824,413✔
1261
        if (pCol->hasNull && colDataIsNull_f(pCol->nullbitmap, i)) {
1,781,557✔
1262
          continue;
343,215✔
1263
        }
1264

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

1273
    default:
×
1274
      break;
×
1275
  }
1276

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

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

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

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

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

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

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

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

1401
  if (pStddevRes->count == 0) {
291,370✔
1402
    GET_RES_INFO(pCtx)->numOfRes = 0;
49,705✔
1403
    return functionFinalize(pCtx, pBlock);
49,705✔
1404
  }
1405

1406
  if (IS_SIGNED_NUMERIC_TYPE(type)) {
241,665!
1407
    avg = pStddevRes->isum / ((double)pStddevRes->count);
206,471✔
1408
    pStddevRes->result = sqrt(fabs(pStddevRes->quadraticISum / ((double)pStddevRes->count) - avg * avg));
206,471✔
1409
  } else if (IS_UNSIGNED_NUMERIC_TYPE(type)) {
35,194!
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);
35,192✔
1414
    pStddevRes->result = sqrt(fabs(pStddevRes->quadraticDSum / ((double)pStddevRes->count) - avg * avg));
35,192✔
1415
  }
1416

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

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

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

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

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

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

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

1508
  SLeastSQRInfo* pInfo = GET_ROWCELL_INTERBUF(pResultInfo);
46,613✔
1509

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

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

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

1521
  SLeastSQRInfo* pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
49,296✔
1522

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

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

1528
  int32_t start = pInput->startRowIndex;
49,296✔
1529
  int32_t numOfRows = pInput->numOfRows;
49,296✔
1530

1531
  switch (type) {
49,296!
1532
    case TSDB_DATA_TYPE_TINYINT: {
10,423✔
1533
      int8_t* plist = (int8_t*)pCol->pData;
10,423✔
1534
      for (int32_t i = start; i < numOfRows + pInput->startRowIndex; ++i) {
299,589✔
1535
        if (pCol->hasNull && colDataIsNull_f(pCol->nullbitmap, i)) {
289,166✔
1536
          continue;
2,436✔
1537
        }
1538
        numOfElem++;
286,730✔
1539
        LEASTSQR_CAL(param, x, plist, i, pInfo->stepVal);
286,730✔
1540
      }
1541
      break;
10,423✔
1542
    }
1543
    case TSDB_DATA_TYPE_SMALLINT: {
4,684✔
1544
      int16_t* plist = (int16_t*)pCol->pData;
4,684✔
1545
      for (int32_t i = start; i < numOfRows + pInput->startRowIndex; ++i) {
10,136✔
1546
        if (pCol->hasNull && colDataIsNull_f(pCol->nullbitmap, i)) {
5,452✔
1547
          continue;
3,036✔
1548
        }
1549

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

1556
    case TSDB_DATA_TYPE_INT: {
10,476✔
1557
      int32_t* plist = (int32_t*)pCol->pData;
10,476✔
1558
      for (int32_t i = start; i < numOfRows + pInput->startRowIndex; ++i) {
446,653✔
1559
        if (pCol->hasNull && colDataIsNull_f(pCol->nullbitmap, i)) {
436,177✔
1560
          continue;
2,284✔
1561
        }
1562

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

1569
    case TSDB_DATA_TYPE_BIGINT: {
4,688✔
1570
      int64_t* plist = (int64_t*)pCol->pData;
4,688✔
1571
      for (int32_t i = start; i < numOfRows + pInput->startRowIndex; ++i) {
10,940✔
1572
        if (pCol->hasNull && colDataIsNull_f(pCol->nullbitmap, i)) {
6,252✔
1573
          continue;
3,036✔
1574
        }
1575

1576
        numOfElem++;
3,216✔
1577
        LEASTSQR_CAL(param, x, plist, i, pInfo->stepVal);
3,216✔
1578
      }
1579
      break;
4,688✔
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: {
13,652✔
1633
      float* plist = (float*)pCol->pData;
13,652✔
1634
      for (int32_t i = start; i < numOfRows + pInput->startRowIndex; ++i) {
449,764✔
1635
        if (pCol->hasNull && colDataIsNull_f(pCol->nullbitmap, i)) {
436,112✔
1636
          continue;
296,196✔
1637
        }
1638

1639
        numOfElem++;
139,916✔
1640
        LEASTSQR_CAL(param, x, plist, i, pInfo->stepVal);
139,916✔
1641
      }
1642
      break;
13,652✔
1643
    }
1644

1645
    case TSDB_DATA_TYPE_DOUBLE: {
5,058✔
1646
      double* plist = (double*)pCol->pData;
5,058✔
1647
      for (int32_t i = start; i < numOfRows + pInput->startRowIndex; ++i) {
13,674✔
1648
        if (pCol->hasNull && colDataIsNull_f(pCol->nullbitmap, i)) {
8,616✔
1649
          continue;
2,436✔
1650
        }
1651

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

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

1667
  pInfo->startVal = x;
49,296✔
1668
  pInfo->num += numOfElem;
49,296✔
1669

1670
  SET_VAL(GET_RES_INFO(pCtx), numOfElem, 1);
49,296✔
1671

1672
  return TSDB_CODE_SUCCESS;
49,296✔
1673
}
1674

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

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

1686
  if (0 == pInfo->num) {
46,630✔
1687
    colDataSetNULL(pCol, currentRow);
20,450!
1688
    return TSDB_CODE_SUCCESS;
20,450✔
1689
  }
1690

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

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

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

1699
  if (0 == param00) {
26,180✔
1700
    colDataSetNULL(pCol, currentRow);
20,072!
1701
    return TSDB_CODE_SUCCESS;
20,072✔
1702
  }
1703

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

1709
  param12 /= param[1][1];
6,108✔
1710

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

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

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

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

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

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

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

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

1814
  // the first stage, only acquire the min/max value
1815
  if (pInfo->stage == 0) {
10,780✔
1816
    if (pCtx->input.colDataSMAIsSet) {
6,788!
UNCOV
1817
      double tmin = 0.0, tmax = 0.0;
×
UNCOV
1818
      if (IS_SIGNED_NUMERIC_TYPE(type)) {
×
1819
        tmin = (double)GET_INT64_VAL(&pAgg->min);
×
1820
        tmax = (double)GET_INT64_VAL(&pAgg->max);
×
UNCOV
1821
      } else if (IS_FLOAT_TYPE(type)) {
×
UNCOV
1822
        tmin = GET_DOUBLE_VAL(&pAgg->min);
×
UNCOV
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

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

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

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

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

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

1854
        if (v > GET_DOUBLE_VAL(&pInfo->maxval)) {
308,838✔
1855
          SET_DOUBLE_VAL(&pInfo->maxval, v);
247,804✔
1856
        }
1857

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

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

1878
    SET_VAL(pResInfo, numOfElems, 1);
3,992!
1879
  }
1880

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

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

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

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

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

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

1943
      tMemBucketDestroy(pMemBucket);
2,972✔
1944
      return functionFinalize(pCtx, pBlock);
2,972✔
1945
    }
1946
  } else {
1947
    return functionFinalize(pCtx, pBlock);
2,738✔
1948
  }
1949

1950
_fin_error:
×
1951

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

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

1964
int32_t getApercentileMaxSize() {
9,946✔
1965
  int32_t bytesHist =
9,946✔
1966
      (int32_t)(sizeof(SAPercentileInfo) + sizeof(SHistogramInfo) + sizeof(SHistBin) * (MAX_HISTOGRAM_BIN + 1));
1967
  int32_t bytesDigest = (int32_t)(sizeof(SAPercentileInfo) + TDIGEST_SIZE(COMPRESSION));
9,946✔
1968
  return TMAX(bytesHist, bytesDigest);
9,946✔
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,148✔
1975
  } else if (strcasecmp(algoStr, "t-digest") == 0) {
11,164✔
1976
    algoType = APERCT_ALGO_TDIGEST;
11,160✔
1977
  } else {
1978
    algoType = APERCT_ALGO_UNKNOWN;
4✔
1979
  }
1980

1981
  return algoType;
22,312✔
1982
}
1983

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

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

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

2001
  SAPercentileInfo* pInfo = GET_ROWCELL_INTERBUF(pResultInfo);
317,464✔
2002

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

2007
  if (pCtx->numOfParams == 2) {
317,464✔
2008
    pInfo->algo = APERCT_ALGO_DEFAULT;
295,158✔
2009
  } else if (pCtx->numOfParams == 3) {
22,306!
2010
    pInfo->algo = getApercentileAlgo(varDataVal(pCtx->param[2].param.pz));
22,316✔
2011
    if (pInfo->algo == APERCT_ALGO_UNKNOWN) {
22,307!
2012
      return TSDB_CODE_FUNC_FUNTION_PARA_VALUE;
×
2013
    }
2014
  }
2015

2016
  char* tmp = (char*)pInfo + sizeof(SAPercentileInfo);
317,455✔
2017
  if (pInfo->algo == APERCT_ALGO_TDIGEST) {
317,455✔
2018
    pInfo->pTDigest = tdigestNewFrom(tmp, COMPRESSION);
11,159✔
2019
  } else {
2020
    buildHistogramInfo(pInfo);
306,296✔
2021
    pInfo->pHisto = tHistogramCreateFrom(tmp, MAX_HISTOGRAM_BIN);
306,308✔
2022
    qDebug("%s set up histogram, numOfElems:%" PRId64 ", numOfEntry:%d, pHisto:%p, elems:%p", __FUNCTION__,
306,298✔
2023
           pInfo->pHisto->numOfElems, pInfo->pHisto->numOfEntries, pInfo->pHisto, pInfo->pHisto->elems);
2024
  }
2025

2026
  return TSDB_CODE_SUCCESS;
317,464✔
2027
}
2028

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

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

2037
  SAPercentileInfo* pInfo = GET_ROWCELL_INTERBUF(pResInfo);
322,953✔
2038

2039
  int32_t start = pInput->startRowIndex;
322,953✔
2040
  if (pInfo->algo == APERCT_ALGO_TDIGEST) {
322,953✔
2041
    buildTDigestInfo(pInfo);
11,152✔
2042
    tdigestAutoFill(pInfo->pTDigest, COMPRESSION);
11,150✔
2043
    for (int32_t i = start; i < pInput->numOfRows + start; ++i) {
581,926✔
2044
      if (colDataIsNull_f(pCol->nullbitmap, i)) {
570,784✔
2045
        continue;
146,973✔
2046
      }
2047
      numOfElems += 1;
423,811✔
2048
      char* data = colDataGetData(pCol, i);
423,811!
2049

2050
      double  v = 0;  // value
423,811✔
2051
      int64_t w = 1;  // weigth
423,811✔
2052
      GET_TYPED_DATA(v, double, type, data);
423,811✔
2053
      int32_t code = tdigestAdd(pInfo->pTDigest, v, w);
423,811✔
2054
      if (code != TSDB_CODE_SUCCESS) {
423,802!
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);
311,801✔
2062
    qDebug("%s before add %d elements into histogram, total:%" PRId64 ", numOfEntry:%d, pHisto:%p, elems: %p",
311,798✔
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,426,448✔
2066
      if (colDataIsNull_f(pCol->nullbitmap, i)) {
2,114,584✔
2067
        continue;
538,639✔
2068
      }
2069
      numOfElems += 1;
1,575,945✔
2070
      char* data = colDataGetData(pCol, i);
1,575,945!
2071

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

2198
  if (pInfo->algo == APERCT_ALGO_TDIGEST) {
281,504✔
2199
    buildTDigestInfo(pInfo);
11,069✔
2200
    tdigestAutoFill(pInfo->pTDigest, COMPRESSION);
11,070✔
2201
    if (pInfo->pTDigest->size > 0) {
11,071!
2202
      pInfo->result = tdigestQuantile(pInfo->pTDigest, pInfo->percent / 100);
11,071✔
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);
270,435✔
2209
    if (pInfo->pHisto->numOfElems > 0) {
270,436✔
2210
      qDebug("%s get the final res, elements:%" PRId64 ", numOfEntry:%d, pHisto:%p, elems:%p", __FUNCTION__,
219,105✔
2211
             pInfo->pHisto->numOfElems, pInfo->pHisto->numOfEntries, pInfo->pHisto, pInfo->pHisto->elems);
2212

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

2231
  return functionFinalize(pCtx, pBlock);
281,506✔
2232
}
2233

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

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

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

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

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

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

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

2315
  SFirstLastRes* pResult = GET_ROWCELL_INTERBUF(pEntry);
997✔
2316
  if (pResult->hasResult) {
997✔
2317
    if (pResult->pkBytes > 0) {
939✔
2318
      pResult->pkData = pResult->buf + pResult->bytes;
6✔
2319
    } else {
2320
      pResult->pkData = NULL;
933✔
2321
    }
2322
    if (pResult->ts < pBlockInfo->window.skey) {
939✔
2323
      return FUNC_DATA_REQUIRED_NOT_LOAD;
224✔
2324
    } else if (pResult->ts == pBlockInfo->window.skey) {
715✔
2325
      if (NULL == pResult->pkData) {
196✔
2326
        return FUNC_DATA_REQUIRED_NOT_LOAD;
190✔
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;
58✔
2335
  }
2336
}
2337

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

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

2346
  SFirstLastRes* pResult = GET_ROWCELL_INTERBUF(pEntry);
1,420✔
2347
  if (pResult->hasResult) {
1,420✔
2348
    if (pResult->pkBytes > 0) {
1,358✔
2349
      pResult->pkData = pResult->buf + pResult->bytes;
5✔
2350
    } else {
2351
      pResult->pkData = NULL;
1,353✔
2352
    }
2353
    if (pResult->ts > pBlockInfo->window.ekey) {
1,358✔
2354
      return FUNC_DATA_REQUIRED_NOT_LOAD;
375✔
2355
    } else if (pResult->ts == pBlockInfo->window.ekey && pResult->pkData) {
983✔
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;
983✔
2361
  } else {
2362
    return FUNC_DATA_REQUIRED_DATA_LOAD;
62✔
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,258,809✔
2368

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

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

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

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

2394
  return *(TSKEY*)colDataGetData(pTsColInfo, rowIndex);
108,266,277!
2395
}
2396

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

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

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

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

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

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

2434
  if (pCtx->subsidiaries.num <= 0) {
60,847,271!
2435
    return TSDB_CODE_SUCCESS;
60,855,915✔
2436
  }
2437

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

2444
  return code;
10,557✔
2445
}
2446

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

2452
  if (IS_VAR_DATA_TYPE(type)) {
35,909,415!
2453
    if (type == TSDB_DATA_TYPE_JSON) {
542,112!
2454
      pInfo->bytes = getJsonValueLen(pData);
×
2455
    } else {
2456
      pInfo->bytes = varDataTLen(pData);
542,112✔
2457
    }
2458
  }
2459

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

2479
  pInfo->hasResult = true;
36,014,846✔
2480
  return TSDB_CODE_SUCCESS;
36,014,846✔
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,556,877✔
2486
  int32_t numOfElems = 0;
29,556,877✔
2487

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

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

2494
  pInfo->bytes = pInputCol->info.bytes;
29,556,877✔
2495

2496
  if (IS_NULL_TYPE(pInputCol->info.type)) {
29,556,877✔
2497
    return TSDB_CODE_SUCCESS;
2,039✔
2498
  }
2499

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

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

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

2581
  int     from = -1;
29,608,257✔
2582
  int32_t i = -1;
29,608,257✔
2583
  while (funcInputGetNextRowIndex(pInput, from, true, &i, &from)) {
79,231,240✔
2584
    if (pInputCol->hasNull && colDataIsNull(pInputCol, pInput->totalRows, i, pColAgg)) {
63,680,577!
2585
      continue;
70,361✔
2586
    }
2587

2588
    numOfElems++;
49,571,440✔
2589
    char* data = colDataGetData(pInputCol, i);
49,571,440!
2590
    char* pkData = NULL;
49,571,440✔
2591
    if (pCtx->hasPrimaryKey) {
49,571,440✔
2592
      pkData = colDataGetData(pkCol, i);
153!
2593
    }
2594
    TSKEY cts = pts[i];
49,571,440✔
2595
    if (pResInfo->numOfRes == 0 || pInfo->ts > cts ||
49,571,440✔
2596
        (pInfo->ts == cts && pkCompareFn && pkCompareFn(pkData, pInfo->pkData) < 0)) {
29,588,047!
2597
      int32_t code = doSaveCurrentVal(pCtx, i, cts, pkData, pInputCol->info.type, data);
19,983,393✔
2598
      if (code != TSDB_CODE_SUCCESS) {
19,964,575!
2599
        return code;
×
2600
      }
2601
      pResInfo->numOfRes = 1;
19,964,575✔
2602
    }
2603
  }
2604
#endif
2605

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

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

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

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

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

2631
  if (IS_NULL_TYPE(type)) {
24,212,891✔
2632
    return TSDB_CODE_SUCCESS;
2,039✔
2633
  }
2634

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

2658
  TSKEY startKey = getRowPTs(pInput->pPTS, 0);
24,297,382!
2659
  TSKEY endKey = getRowPTs(pInput->pPTS, pInput->totalRows - 1);
24,297,382!
2660

2661
  int32_t blockDataOrder = (startKey <= endKey) ? TSDB_ORDER_ASC : TSDB_ORDER_DESC;
24,297,382✔
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;
24,297,382✔
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) {
38,408,410✔
2717
    numOfElems = 1;
14,106,264✔
2718

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

2722
    for (int32_t i = pInput->startRowIndex, tick = 0; tick < round; i += 4, tick += 1) {
22,394,428✔
2723
      int64_t cts = pts[i];
8,291,925✔
2724
      int32_t chosen = i;
8,291,925✔
2725

2726
      if (cts < pts[i + 1]) {
8,291,925✔
2727
        cts = pts[i + 1];
4,787,976✔
2728
        chosen = i + 1;
4,787,976✔
2729
      }
2730

2731
      if (cts < pts[i + 2]) {
8,291,925✔
2732
        cts = pts[i + 2];
4,788,443✔
2733
        chosen = i + 2;
4,788,443✔
2734
      }
2735

2736
      if (cts < pts[i + 3]) {
8,291,925✔
2737
        cts = pts[i + 3];
4,788,637✔
2738
        chosen = i + 3;
4,788,637✔
2739
      }
2740

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

2751
    for (int32_t i = pInput->startRowIndex + round * 4; i < pInput->startRowIndex + pInput->numOfRows; ++i) {
29,699,465✔
2752
      if (pResInfo->numOfRes == 0 || pInfo->ts < pts[i]) {
15,588,437✔
2753
        char*   data = colDataGetData(pInputCol, i);
7,285,078!
2754
        int32_t code = doSaveCurrentVal(pCtx, i, pts[i], NULL, type, data);
7,285,078✔
2755
        if (code != TSDB_CODE_SUCCESS) {
7,293,603!
2756
          return code;
×
2757
        }
2758
        pResInfo->numOfRes = 1;
7,293,603✔
2759
      }
2760
    }
2761
  } else {
2762
    int     from = -1;
10,191,118✔
2763
    int32_t i = -1;
10,191,118✔
2764
    while (funcInputGetNextRowIndex(pInput, from, false, &i, &from)) {
162,445,799✔
2765
      if (colDataIsNull(pInputCol, pInput->totalRows, i, pColAgg)) {
304,549,796✔
2766
        continue;
7,483,785✔
2767
      }
2768

2769
      numOfElems++;
144,791,113✔
2770
      char* pkData = NULL;
144,791,113✔
2771
      if (pCtx->hasPrimaryKey) {
144,791,113✔
2772
        pkData = colDataGetData(pkCol, i);
100,000,193!
2773
      }
2774
      if (pResInfo->numOfRes == 0 || pInfo->ts < pts[i] ||
144,791,113✔
2775
          (pInfo->ts == pts[i] && pkCompareFn && pkCompareFn(pkData, pInfo->pkData) < 0)) {
140,011,985!
2776
        char*   data = colDataGetData(pInputCol, i);
5,099,147!
2777
        int32_t code = doSaveCurrentVal(pCtx, i, pts[i], pkData, type, data);
5,099,147✔
2778
        if (code != TSDB_CODE_SUCCESS) {
5,078,930!
2779
          return code;
×
2780
        }
2781
        pResInfo->numOfRes = 1;
5,078,930✔
2782
      }
2783
    }
2784
  }
2785
#endif
2786

2787
#endif
2788

2789
  // save selectivity value for column consisted of all null values
2790
  if (numOfElems == 0) {
24,285,691✔
2791
    int32_t code = firstlastSaveTupleData(pCtx->pSrcBlock, pInput->startRowIndex, pCtx, pInfo, !pInfo->nullTupleSaved);
4,076,942✔
2792
    if (code != TSDB_CODE_SUCCESS) {
4,065,807!
2793
      return code;
×
2794
    }
2795
    pInfo->nullTupleSaved = true;
4,065,807✔
2796
  }
2797

2798
  return TSDB_CODE_SUCCESS;
24,274,556✔
2799
}
2800

2801
static bool firstLastTransferInfoImpl(SFirstLastRes* pInput, SFirstLastRes* pOutput, bool isFirst) {
21,030,767✔
2802
  if (!pInput->hasResult) {
21,030,767✔
2803
    return false;
2✔
2804
  }
2805
  __compar_fn_t pkCompareFn = NULL;
21,030,765✔
2806
  if (pInput->pkData) {
21,030,765✔
2807
    pkCompareFn = getKeyComparFunc(pInput->pkType, (isFirst) ? TSDB_ORDER_ASC : TSDB_ORDER_DESC);
52✔
2808
  }
2809
  if (pOutput->hasResult) {
21,030,765✔
2810
    if (isFirst) {
13,302,421✔
2811
      if (pInput->ts > pOutput->ts ||
8,571,756✔
2812
          (pInput->ts == pOutput->ts && pkCompareFn && pkCompareFn(pInput->pkData, pOutput->pkData) > 0)) {
8,571,176!
2813
        return false;
580✔
2814
      }
2815
    } else {
2816
      if (pInput->ts < pOutput->ts ||
4,730,665✔
2817
          (pInput->ts == pOutput->ts && pkCompareFn && pkCompareFn(pInput->pkData, pOutput->pkData) > 0)) {
4,648,527!
2818
        return false;
82,138✔
2819
      }
2820
    }
2821
  }
2822

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

2828
  (void)memcpy(pOutput->buf, pInput->buf, pOutput->bytes);
20,948,047✔
2829
  if (pInput->pkData) {
20,948,047✔
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,047✔
2835
}
2836

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

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

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

2862
  SFirstLastRes* pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
7,744,965✔
2863

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

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

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

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

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

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

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

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

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

2915
  SFirstLastRes* pRes = GET_ROWCELL_INTERBUF(pResInfo);
9,344,807✔
2916

2917
  if (pResInfo->isNullRes) {
9,344,807✔
2918
    colDataSetNULL(pCol, pBlock->info.rows);
34,530✔
2919
    return setSelectivityValue(pCtx, pBlock, &pRes->nullTuplePos, pBlock->info.rows);
34,530✔
2920
  }
2921
  code = colDataSetVal(pCol, pBlock->info.rows, pRes->buf, pRes->isNull || pResInfo->isNullRes);
9,310,277✔
2922
  if (TSDB_CODE_SUCCESS != code) {
9,310,282!
2923
    return code;
×
2924
  }
2925

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

2929
  return code;
9,310,283✔
2930
}
2931

2932
int32_t firstLastPartialFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
25,059,298✔
2933
  int32_t code = TSDB_CODE_SUCCESS;
25,059,298✔
2934

2935
  SResultRowEntryInfo* pEntryInfo = GET_RES_INFO(pCtx);
25,059,298✔
2936
  SFirstLastRes*       pRes = GET_ROWCELL_INTERBUF(pEntryInfo);
25,059,298✔
2937

2938
  int32_t resultBytes = getFirstLastInfoSize(pRes->bytes, pRes->pkBytes);
25,059,298✔
2939

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

2947
  varDataSetLen(res, resultBytes);
25,318,976✔
2948

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

2956
  if (pEntryInfo->numOfRes == 0) {
25,238,424✔
2957
    colDataSetNULL(pCol, pBlock->info.rows);
2,358,839!
2958
    code = setSelectivityValue(pCtx, pBlock, &pRes->nullTuplePos, pBlock->info.rows);
2,358,839✔
2959
  } else {
2960
    code = colDataSetVal(pCol, pBlock->info.rows, res, false);
22,879,585✔
2961
    if (TSDB_CODE_SUCCESS != code) {
22,559,479!
2962
      taosMemoryFree(res);
×
2963
      return code;
×
2964
    }
2965
    code = setSelectivityValue(pCtx, pBlock, &pRes->pos, pBlock->info.rows);
22,559,479✔
2966
  }
2967
  taosMemoryFree(res);
24,867,390✔
2968
  return code;
25,413,588✔
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,901✔
2986
  SInputColumnInfoData* pInput = &pCtx->input;
11,901✔
2987
  SColumnInfoData*      pInputCol = pInput->pData[0];
11,901✔
2988
  SColumnInfoData*      pkCol = pInput->pPrimaryKey;
11,901✔
2989

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

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

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

3006
  if (pCtx->hasPrimaryKey && !colDataIsNull_s(pkCol, rowIndex)) {
11,974!
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,901✔
3019
  int32_t code = firstlastSaveTupleData(pCtx->pSrcBlock, rowIndex, pCtx, pInfo, false);
11,901✔
3020
  if (code != TSDB_CODE_SUCCESS) {
11,901!
3021
    return code;
×
3022
  }
3023

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

3026
  return TSDB_CODE_SUCCESS;
11,901✔
3027
}
3028

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

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

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

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

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

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

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

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

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

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

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

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

3175
static bool diffIsNegtive(SDiffInfo* pDiffInfo, int32_t type, const char* pv) {
28,297✔
3176
  switch (type) {
28,297!
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: {
4,210✔
3182
      int64_t v = *(int32_t*)pv;
4,210✔
3183
      return v < pDiffInfo->prev.i64;
4,210✔
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: {
3,633✔
3194
      int64_t v = *(int8_t*)pv;
3,633✔
3195
      return v < pDiffInfo->prev.i64;
3,633✔
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: {
4,880✔
3202
      int64_t v = *(int16_t*)pv;
4,880✔
3203
      return v < pDiffInfo->prev.i64;
4,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:
6,465✔
3210
    case TSDB_DATA_TYPE_BIGINT: {
3211
      int64_t v = *(int64_t*)pv;
6,465✔
3212
      return v < pDiffInfo->prev.i64;
6,465✔
3213
    }
3214
    case TSDB_DATA_TYPE_FLOAT: {
4,844✔
3215
      float v = *(float*)pv;
4,844✔
3216
      return v < pDiffInfo->prev.d64;
4,844✔
3217
    }
3218
    case TSDB_DATA_TYPE_DOUBLE: {
4,241✔
3219
      double v = *(double*)pv;
4,241✔
3220
      return v < pDiffInfo->prev.d64;
4,241✔
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,003,081✔
3230
  bool isNegative = v < pDiffInfo->prev.i64;
16,003,081✔
3231
  if (type == TSDB_DATA_TYPE_UBIGINT) {
16,003,081✔
3232
    isNegative = (uint64_t)v < (uint64_t)pDiffInfo->prev.i64;
453✔
3233
  }
3234
  int64_t delta = v - pDiffInfo->prev.i64;
16,003,081✔
3235
  if (isNegative && ignoreNegative(pDiffInfo->ignoreOption)) {
16,003,081✔
3236
    colDataSetNull_f_s(pOutput, pos);
9,546✔
3237
    pOutput->hasNull = true;
9,546✔
3238
  } else {
3239
    colDataSetInt64(pOutput, pos, &delta);
15,993,535✔
3240
  }
3241
  pDiffInfo->prev.i64 = v;
16,003,081✔
3242
}
16,003,081✔
3243

3244
static void tryToSetDouble(SDiffInfo* pDiffInfo, SColumnInfoData* pOutput, double v, int32_t pos) {
92,341✔
3245
  double delta = v - pDiffInfo->prev.d64;
92,341✔
3246
  if (delta < 0 && ignoreNegative(pDiffInfo->ignoreOption)) {
92,341✔
3247
    colDataSetNull_f_s(pOutput, pos);
4,547✔
3248
  } else {
3249
    colDataSetDouble(pOutput, pos, &delta);
87,794✔
3250
  }
3251
  pDiffInfo->prev.d64 = v;
92,341✔
3252
}
92,341✔
3253

3254
static int32_t doHandleDiff(SDiffInfo* pDiffInfo, int32_t type, const char* pv, SColumnInfoData* pOutput, int32_t pos,
16,095,865✔
3255
                            int64_t ts) {
3256
  if (!pDiffInfo->hasPrev) {
16,095,865✔
3257
    colDataSetNull_f_s(pOutput, pos);
443✔
3258
    return doSetPrevVal(pDiffInfo, type, pv, ts);
443✔
3259
  }
3260
  pDiffInfo->prevTs = ts;
16,095,422✔
3261
  switch (type) {
16,095,422!
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,784,225✔
3268
      int64_t v = *(int32_t*)pv;
15,784,225✔
3269
      tryToSetInt64(pDiffInfo, type, pOutput, v, pos);
15,784,225✔
3270
      break;
15,784,225✔
3271
    }
3272
    case TSDB_DATA_TYPE_BOOL: {
10,560✔
3273
      int64_t v = *(bool*)pv;
10,560✔
3274
      tryToSetInt64(pDiffInfo, type, pOutput, v, pos);
10,560✔
3275
      break;
10,560✔
3276
    }
3277
    case TSDB_DATA_TYPE_UTINYINT: {
405✔
3278
      int64_t v = *(uint8_t*)pv;
405✔
3279
      tryToSetInt64(pDiffInfo, type, pOutput, v, pos);
405✔
3280
      break;
405✔
3281
    }
3282
    case TSDB_DATA_TYPE_TINYINT: {
33,623✔
3283
      int64_t v = *(int8_t*)pv;
33,623✔
3284
      tryToSetInt64(pDiffInfo, type, pOutput, v, pos);
33,623✔
3285
      break;
33,623✔
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: {
32,317✔
3293
      int64_t v = *(int16_t*)pv;
32,317✔
3294
      tryToSetInt64(pDiffInfo, type, pOutput, v, pos);
32,317✔
3295
      break;
32,317✔
3296
    }
3297
    case TSDB_DATA_TYPE_TIMESTAMP:
141,135✔
3298
    case TSDB_DATA_TYPE_UBIGINT:
3299
    case TSDB_DATA_TYPE_BIGINT: {
3300
      int64_t v = *(int64_t*)pv;
141,135✔
3301
      tryToSetInt64(pDiffInfo, type, pOutput, v, pos);
141,135✔
3302
      break;
141,135✔
3303
    }
3304
    case TSDB_DATA_TYPE_FLOAT: {
41,967✔
3305
      double v = *(float*)pv;
41,967✔
3306
      tryToSetDouble(pDiffInfo, pOutput, v, pos);
41,967✔
3307
      break;
41,967✔
3308
    }
3309
    case TSDB_DATA_TYPE_DOUBLE: {
50,374✔
3310
      double v = *(double*)pv;
50,374✔
3311
      tryToSetDouble(pDiffInfo, pOutput, v, pos);
50,374✔
3312
      break;
50,374✔
3313
    }
3314
    default:
×
3315
      return TSDB_CODE_FUNC_FUNTION_PARA_TYPE;
×
3316
  }
3317
  pDiffInfo->hasPrev = true;
16,095,422✔
3318
  return TSDB_CODE_SUCCESS;
16,095,422✔
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,
240,842,349✔
3324
                              int32_t* nextFrom) {
3325
  if (pInput->pPrimaryKey == NULL) {
240,842,349✔
3326
    if (from == -1) {
140,916,324✔
3327
      from = pInput->startRowIndex;
40,990,053✔
3328
    } else if (from >= pInput->numOfRows + pInput->startRowIndex) {
99,926,271✔
3329
      return false;
40,644,724✔
3330
    }
3331
    *pRowIndex = from;
100,271,600✔
3332
    *nextFrom = from + 1;
100,271,600✔
3333
    return true;
100,271,600✔
3334
  } else {
3335
    if (from == -1) {
99,926,025✔
3336
      from = pInput->startRowIndex;
30,175✔
3337
    } else if (from >= pInput->numOfRows + pInput->startRowIndex) {
99,895,850✔
3338
      return false;
30,175✔
3339
    }
3340
    TSKEY*           tsList = (int64_t*)pInput->pPTS->pData;
99,895,850✔
3341
    SColumnInfoData* pkCol = pInput->pPrimaryKey;
99,895,850✔
3342
    int8_t           pkType = pkCol->info.type;
99,895,850✔
3343
    int32_t          order = (firstOccur) ? TSDB_ORDER_ASC : TSDB_ORDER_DESC;
99,895,850✔
3344
    __compar_fn_t    compareFunc = getKeyComparFunc(pkType, order);
99,895,850✔
3345
    int32_t          select = from;
100,000,517✔
3346
    char*            val = colDataGetData(pkCol, select);
100,000,517!
3347
    while (from < pInput->numOfRows + pInput->startRowIndex - 1 && tsList[from + 1] == tsList[from]) {
100,001,072✔
3348
      char* val1 = colDataGetData(pkCol, from + 1);
555!
3349
      if (compareFunc(val1, val) < 0) {
555!
3350
        select = from + 1;
×
3351
        val = val1;
×
3352
      }
3353
      from = from + 1;
555✔
3354
    }
3355
    *pRowIndex = select;
100,000,517✔
3356
    *nextFrom = from + 1;
100,000,517✔
3357
    return true;
100,000,517✔
3358
  }
3359
}
3360

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

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

3370
  if (pRow->isDataNull || !pDiffInfo->hasPrev) {
16,221,856✔
3371
    return true;
126,362✔
3372
  } else if (ignoreNegative(pDiffInfo->ignoreOption)) {
16,095,494✔
3373
    return diffIsNegtive(pDiffInfo, pCtx->input.pData[0]->info.type, pRow->pData);
28,297✔
3374
  }
3375
  return false;
16,067,197✔
3376
}
3377

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

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

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

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

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

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

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

3423
  char* pv = pRow->pData;
16,095,886✔
3424

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

3440
  return TSDB_CODE_SUCCESS;
16,095,865✔
3441
}
3442

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

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

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

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

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

3512
    bool newRow = false;
16,207,362✔
3513
    for (int i = 0; i < diffColNum; ++i) {
32,429,197✔
3514
      SqlFunctionCtx* pCtx = *(SqlFunctionCtx**)taosArrayGet(pCtxArray, i);
16,221,856✔
3515
      SFuncInputRow*  pRow = (SFuncInputRow*)taosArrayGet(pRows, i);
16,221,856✔
3516
      if (NULL == pCtx || NULL == pRow) {
16,221,856!
3517
        code = terrno;
×
3518
        goto _exit;
×
3519
      }
3520
      if ((keepNull || hasNotNullValue) && !isFirstRow(pCtx, pRow)) {
16,221,856✔
3521
        code = setDoDiffResult(pCtx, pRow, pos);
16,186,898✔
3522
        if (code != TSDB_CODE_SUCCESS) {
16,186,898✔
3523
          goto _exit;
21✔
3524
        }
3525
        newRow = true;
16,186,877✔
3526
      } else {
3527
        code = trySetPreVal(pCtx, pRow);
34,958✔
3528
        if (code != TSDB_CODE_SUCCESS) {
34,958!
3529
          goto _exit;
×
3530
        }
3531
      }
3532
    }
3533
    if (newRow) ++numOfElems;
16,207,341✔
3534
  }
3535

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

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

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

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

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

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

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

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

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

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

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

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

3603
  int32_t start = pInput->startRowIndex;
23,615✔
3604
  for (int32_t i = start; i < pInput->numOfRows + start; ++i) {
365,761✔
3605
    if (pCol->hasNull && colDataIsNull_f(pCol->nullbitmap, i)) {
341,740✔
3606
      continue;
25,586✔
3607
    }
3608

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

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

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

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

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

3637
  int32_t start = pInput->startRowIndex;
3,057✔
3638
  for (int32_t i = start; i < pInput->numOfRows + start; ++i) {
129,392✔
3639
    if (pCol->hasNull && colDataIsNull_f(pCol->nullbitmap, i)) {
126,248✔
3640
      continue;
22,720✔
3641
    }
3642

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

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

3659
  return TSDB_CODE_SUCCESS;
3,144✔
3660
}
3661

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

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

3668
  if (IS_SIGNED_NUMERIC_TYPE(type)) {
1,466,932!
3669
    if (val1->v.i == val2->v.i) {
800,660✔
3670
      return 0;
169,015✔
3671
    }
3672

3673
    return (val1->v.i > val2->v.i) ? 1 : -1;
631,645✔
3674
  } else if (IS_UNSIGNED_NUMERIC_TYPE(type)) {
666,272!
3675
    if (val1->v.u == val2->v.u) {
465,984✔
3676
      return 0;
101,656✔
3677
    }
3678

3679
    return (val1->v.u > val2->v.u) ? 1 : -1;
364,328✔
3680
  } else if (TSDB_DATA_TYPE_FLOAT == type) {
200,288✔
3681
    if (val1->v.f == val2->v.f) {
23,195✔
3682
      return 0;
63✔
3683
    }
3684

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

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

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

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

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

3703
  STopBotResItem* pItems = pRes->pItems;
419,949✔
3704

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

3711
    // save the data of this tuple
3712
    if (pCtx->subsidiaries.num > 0) {
111,754✔
3713
      code = saveTupleData(pCtx, rowIndex, pSrcBlock, &pItem->tuplePos);
44,179✔
3714
      if (code != TSDB_CODE_SUCCESS) {
44,110!
3715
        return code;
×
3716
      }
3717
    }
3718
#ifdef BUF_PAGE_DEBUG
3719
    qDebug("page_saveTuple i:%d, item:%p,pageId:%d, offset:%d\n", pEntryInfo->numOfRes, pItem, pItem->tuplePos.pageId,
3720
           pItem->tuplePos.offset);
3721
#endif
3722
    // allocate the buffer and keep the data of this row into the new allocated buffer
3723
    pEntryInfo->numOfRes++;
111,685✔
3724
    code = taosheapsort((void*)pItems, sizeof(STopBotResItem), pEntryInfo->numOfRes, (const void*)&type,
111,685✔
3725
                        topBotResComparFn, !isTopQuery);
111,685✔
3726
    if (code != TSDB_CODE_SUCCESS) {
112,054!
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) ||
308,195✔
3731
                        (IS_UNSIGNED_NUMERIC_TYPE(type) && val.u > pItems[0].v.u) ||
158,870!
3732
                        (TSDB_DATA_TYPE_FLOAT == type && val.f > pItems[0].v.f) ||
104,317✔
3733
                        (TSDB_DATA_TYPE_DOUBLE == type && val.d > pItems[0].v.d))) ||
104,153✔
3734
        (!isTopQuery && ((IS_SIGNED_NUMERIC_TYPE(type) && val.i < pItems[0].v.i) ||
170,960!
3735
                         (IS_UNSIGNED_NUMERIC_TYPE(type) && val.u < pItems[0].v.u) ||
79,440!
3736
                         (TSDB_DATA_TYPE_FLOAT == type && val.f < pItems[0].v.f) ||
78,409✔
3737
                         (TSDB_DATA_TYPE_DOUBLE == type && val.d < pItems[0].v.d)))) {
76,796✔
3738
      // replace the old data and the coresponding tuple data
3739
      STopBotResItem* pItem = &pItems[0];
146,730✔
3740
      pItem->v = val;
146,730✔
3741
      pItem->uid = uid;
146,730✔
3742

3743
      // save the data of this tuple by over writing the old data
3744
      if (pCtx->subsidiaries.num > 0) {
146,730✔
3745
        code = updateTupleData(pCtx, rowIndex, pSrcBlock, &pItem->tuplePos);
114,617✔
3746
        if (code != TSDB_CODE_SUCCESS) {
114,203!
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,
146,316✔
3754
                            topBotResComparFn, NULL, !isTopQuery);
146,316✔
3755
      if (code != TSDB_CODE_SUCCESS) {
146,734!
3756
        return code;
×
3757
      }
3758
    }
3759
  }
3760

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

3775
  int32_t offset = 0;
383,969✔
3776
  for (int32_t i = 0; i < pSubsidiaryies->num; ++i) {
814,048✔
3777
    SqlFunctionCtx* pc = pSubsidiaryies->pCtx[i];
430,141✔
3778

3779
    // group_key function has its own process function
3780
    // do not process there
3781
    if (fmIsGroupKeyFunc(pc->functionId)) {
430,141✔
3782
      continue;
37,846✔
3783
    }
3784

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

3788
    SColumnInfoData* pCol = taosArrayGet(pSrcBlock->pDataBlock, srcSlotId);
392,253✔
3789
    if (NULL == pCol) {
392,233!
3790
      return TSDB_CODE_OUT_OF_RANGE;
×
3791
    }
3792
    if ((nullList[i] = colDataIsNull_s(pCol, rowIndex)) == true) {
784,466✔
3793
      offset += pCol->info.bytes;
274✔
3794
      continue;
274✔
3795
    }
3796

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

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

3807
  *res = buf;
383,907✔
3808
  return TSDB_CODE_SUCCESS;
383,907✔
3809
}
3810

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

3817
    if (pHandle->currentPage == -1) {
550,293✔
3818
      pPage = getNewBufPage(pHandle->pBuf, &pHandle->currentPage);
18,767✔
3819
      if (pPage == NULL) {
18,769✔
3820
        return terrno;
1✔
3821
      }
3822
      pPage->num = sizeof(SFilePage);
18,768✔
3823
    } else {
3824
      pPage = getBufPage(pHandle->pBuf, pHandle->currentPage);
531,526✔
3825
      if (pPage == NULL) {
531,441!
3826
        return terrno;
×
3827
      }
3828
      if (pPage->num + length > getBufPageSize(pHandle->pBuf)) {
531,441✔
3829
        // current page is all used, let's prepare a new buffer page
3830
        releaseBufPage(pHandle->pBuf, pPage);
6,404✔
3831
        pPage = getNewBufPage(pHandle->pBuf, &pHandle->currentPage);
6,404✔
3832
        if (pPage == NULL) {
6,404!
3833
          return terrno;
×
3834
        }
3835
        pPage->num = sizeof(SFilePage);
6,404✔
3836
      }
3837
    }
3838

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

3842
    pPage->num += length;
550,112✔
3843
    setBufPageDirty(pPage, true);
550,112✔
3844
    releaseBufPage(pHandle->pBuf, pPage);
549,622✔
3845
  } else {  // other tuple save policy
3846
    if (pStore->streamStateFuncPut(pHandle->pState, key, pBuf, length) >= 0) {
62,952!
3847
      p.streamTupleKey = *key;
62,957✔
3848
    }
3849
  }
3850

3851
  *pPos = p;
612,252✔
3852
  return TSDB_CODE_SUCCESS;
612,252✔
3853
}
3854

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

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

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

3882
static int32_t doUpdateTupleData(SSerializeDataHandle* pHandle, const void* pBuf, size_t length, STuplePos* pPos,
236,524✔
3883
                                 SFunctionStateStore* pStore) {
3884
  if (pHandle->pBuf != NULL) {
236,524✔
3885
    SFilePage* pPage = getBufPage(pHandle->pBuf, pPos->pageId);
132,562✔
3886
    if (pPage == NULL) {
132,431!
3887
      return terrno;
×
3888
    }
3889
    (void)memcpy(pPage->data + pPos->offset, pBuf, length);
132,431✔
3890
    setBufPageDirty(pPage, true);
132,431✔
3891
    releaseBufPage(pHandle->pBuf, pPage);
132,391✔
3892
  } else {
3893
    int32_t code = pStore->streamStateFuncPut(pHandle->pState, &pPos->streamTupleKey, pBuf, length);
103,962✔
3894
    if (TSDB_CODE_SUCCESS != code) {
103,965!
3895
      return code;
×
3896
    }
3897
  }
3898

3899
  return TSDB_CODE_SUCCESS;
236,211✔
3900
}
3901

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

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

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

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

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

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

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

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

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

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

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

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

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

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

4086
  SSpreadInfo* pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
295,925✔
4087

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

4116
    int32_t start = pInput->startRowIndex;
295,925✔
4117
    // check the valid data one by one
4118
    for (int32_t i = start; i < pInput->numOfRows + start; ++i) {
5,489,382✔
4119
      if (colDataIsNull_f(pCol->nullbitmap, i)) {
5,193,457✔
4120
        continue;
1,190,761✔
4121
      }
4122

4123
      char* data = colDataGetData(pCol, i);
4,002,696!
4124

4125
      double v = 0;
4,002,696✔
4126
      GET_TYPED_DATA(v, double, type, data);
4,002,696!
4127
      if (v < GET_DOUBLE_VAL(&pInfo->min)) {
4,002,696✔
4128
        SET_DOUBLE_VAL(&pInfo->min, v);
275,836✔
4129
      }
4130

4131
      if (v > GET_DOUBLE_VAL(&pInfo->max)) {
4,002,696✔
4132
        SET_DOUBLE_VAL(&pInfo->max, v);
527,557✔
4133
      }
4134

4135
      numOfElems += 1;
4,002,696✔
4136
    }
4137
  }
4138

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

4146
  return TSDB_CODE_SUCCESS;
295,925✔
4147
}
4148

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

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

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

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

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

4175
  int32_t start = pInput->startRowIndex;
18,264✔
4176
  for (int32_t i = start; i < start + pInput->numOfRows; ++i) {
40,724✔
4177
    if (colDataIsNull_s(pCol, i)) continue;
44,920!
4178
    char*        data = colDataGetData(pCol, i);
22,460!
4179
    SSpreadInfo* pInputInfo = (SSpreadInfo*)varDataVal(data);
22,460✔
4180
    if (pInputInfo->hasResult) {
22,460✔
4181
      spreadTransferInfo(pInputInfo, pInfo);
22,217✔
4182
    }
4183
  }
4184

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

4189
  return TSDB_CODE_SUCCESS;
18,264✔
4190
}
4191

4192
int32_t spreadFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
252,527✔
4193
  SSpreadInfo* pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
252,527✔
4194
  if (pInfo->hasResult == true) {
252,527✔
4195
    SET_DOUBLE_VAL(&pInfo->result, pInfo->max - pInfo->min);
225,539✔
4196
  } else {
4197
    GET_RES_INFO(pCtx)->isNullRes = 1;
26,988✔
4198
  }
4199
  return functionFinalize(pCtx, pBlock);
252,527✔
4200
}
4201

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

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

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

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

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

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

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

4264
  if (pCtx->numOfParams > 1) {
36,161✔
4265
    pInfo->timeUnit = pCtx->param[1].param.i;
21,192✔
4266
  } else {
4267
    pInfo->timeUnit = 1;
14,969✔
4268
  }
4269

4270
  return TSDB_CODE_SUCCESS;
36,161✔
4271
}
4272

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

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

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

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

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

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

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

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

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

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

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

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

4459
  return binType;
7,020✔
4460
}
4461

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

4474
    cJSON* start = cJSON_GetObjectItem(binDesc, "start");
4,042✔
4475
    cJSON* factor = cJSON_GetObjectItem(binDesc, "factor");
4,043✔
4476
    cJSON* width = cJSON_GetObjectItem(binDesc, "width");
4,042✔
4477
    cJSON* count = cJSON_GetObjectItem(binDesc, "count");
4,042✔
4478
    cJSON* infinity = cJSON_GetObjectItem(binDesc, "infinity");
4,043✔
4479

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

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

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

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

4505
    intervals = taosMemoryCalloc(numOfBins, sizeof(double));
4,043!
4506
    if (NULL == intervals) {
4,043!
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) {
4,043!
4512
      // linear bin process
4513
      if (width->valuedouble == 0) {
3,141!
4514
        taosMemoryFree(intervals);
×
4515
        cJSON_Delete(binDesc);
×
4516
        return TSDB_CODE_FAILED;
×
4517
      }
4518
      for (int i = 0; i < counter + 1; ++i) {
19,682✔
4519
        intervals[startIndex] = start->valuedouble + i * width->valuedouble;
16,541✔
4520
        if (isinf(intervals[startIndex])) {
16,541!
4521
          taosMemoryFree(intervals);
×
4522
          cJSON_Delete(binDesc);
×
4523
          return TSDB_CODE_FAILED;
×
4524
        }
4525
        startIndex++;
16,541✔
4526
      }
4527
    } else if (cJSON_IsNumber(factor) && width == NULL && binType == LOG_BIN) {
902!
4528
      // log bin process
4529
      if (start->valuedouble == 0) {
902!
4530
        taosMemoryFree(intervals);
×
4531
        cJSON_Delete(binDesc);
×
4532
        return TSDB_CODE_FAILED;
×
4533
      }
4534
      if (factor->valuedouble < 0 || factor->valuedouble == 0 || factor->valuedouble == 1) {
902!
UNCOV
4535
        taosMemoryFree(intervals);
×
4536
        cJSON_Delete(binDesc);
×
4537
        return TSDB_CODE_FAILED;
×
4538
      }
4539
      for (int i = 0; i < counter + 1; ++i) {
4,009✔
4540
        intervals[startIndex] = start->valuedouble * pow(factor->valuedouble, i * 1.0);
3,107✔
4541
        if (isinf(intervals[startIndex])) {
3,107!
4542
          taosMemoryFree(intervals);
×
4543
          cJSON_Delete(binDesc);
×
4544
          return TSDB_CODE_FAILED;
×
4545
        }
4546
        startIndex++;
3,107✔
4547
      }
4548
    } else {
UNCOV
4549
      taosMemoryFree(intervals);
×
4550
      cJSON_Delete(binDesc);
×
4551
      return TSDB_CODE_FAILED;
×
4552
    }
4553

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

4604
  pInfo->numOfBins = numOfBins - 1;
7,020✔
4605
  pInfo->normalized = normalized;
7,020✔
4606
  for (int32_t i = 0; i < pInfo->numOfBins; ++i) {
31,184✔
4607
    pInfo->bins[i].lower = intervals[i] < intervals[i + 1] ? intervals[i] : intervals[i + 1];
24,164✔
4608
    pInfo->bins[i].upper = intervals[i + 1] > intervals[i] ? intervals[i + 1] : intervals[i];
24,164✔
4609
    pInfo->bins[i].count = 0;
24,164✔
4610
  }
4611

4612
  taosMemoryFree(intervals);
7,020!
4613
  cJSON_Delete(binDesc);
7,020✔
4614

4615
  return TSDB_CODE_SUCCESS;
7,020✔
4616
}
4617

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

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

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

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

4657
  return TSDB_CODE_SUCCESS;
7,020✔
4658
}
4659

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

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

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

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

4671
  int32_t numOfElems = 0;
7,926✔
4672
  for (int32_t i = start; i < numOfRows + start; ++i) {
1,203,525✔
4673
    if (pCol->hasNull && colDataIsNull_f(pCol->nullbitmap, i)) {
1,195,599✔
4674
      continue;
391,106✔
4675
    }
4676

4677
    numOfElems++;
804,493✔
4678

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

4683
    for (int32_t k = 0; k < pInfo->numOfBins; ++k) {
3,062,925✔
4684
      if (v > pInfo->bins[k].lower && v <= pInfo->bins[k].upper) {
2,630,605✔
4685
        pInfo->bins[k].count++;
372,173✔
4686
        pInfo->totalCount++;
372,173✔
4687
        break;
372,173✔
4688
      }
4689
    }
4690
  }
4691

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

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

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

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

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

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

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

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

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

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

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

4748
  if (pInfo->normalized) {
6,924✔
4749
    for (int32_t k = 0; k < pResInfo->numOfRes; ++k) {
16,622✔
4750
      if (pInfo->totalCount != 0) {
12,157✔
4751
        pInfo->bins[k].percentage = pInfo->bins[k].count / (double)pInfo->totalCount;
3,137✔
4752
      } else {
4753
        pInfo->bins[k].percentage = 0;
9,020✔
4754
      }
4755
    }
4756
  }
4757

4758
  for (int32_t i = 0; i < pResInfo->numOfRes; ++i) {
30,605✔
4759
    int32_t len;
4760
    char    buf[512] = {0};
23,682✔
4761
    if (!pInfo->normalized) {
23,682✔
4762
      len = tsnprintf(varDataVal(buf), sizeof(buf) - VARSTR_HEADER_SIZE,
11,525✔
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,
12,157✔
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);
23,680✔
4771
    code = colDataSetVal(pCol, currentRow, buf, false);
23,680✔
4772
    if (TSDB_CODE_SUCCESS != code) {
23,681!
4773
      return code;
×
4774
    }
4775
    currentRow++;
23,681✔
4776
  }
4777

4778
  return code;
6,923✔
4779
}
4780

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

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

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

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

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

4827
static uint8_t hllCountNum(void* data, int32_t bytes, int32_t* buk) {
3,793,385✔
4828
  uint64_t hash = MurmurHash3_64(data, bytes);
3,793,385✔
4829
  int32_t  index = hash & HLL_BUCKET_MASK;
3,792,572✔
4830
  hash >>= HLL_BUCKET_BITS;
3,792,572✔
4831
  hash |= ((uint64_t)1 << HLL_DATA_BITS);
3,792,572✔
4832
  uint64_t bit = 1;
3,792,572✔
4833
  uint8_t  count = 1;
3,792,572✔
4834
  while ((hash & bit) == 0) {
6,900,249✔
4835
    count++;
3,107,677✔
4836
    bit <<= 1;
3,107,677✔
4837
  }
4838
  *buk = index;
3,792,572✔
4839
  return count;
3,792,572✔
4840
}
4841

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

4846
  for (int32_t j = 0; j < HLL_BUCKETS >> 3; j++) {
496,135,727✔
4847
    if (*word == 0) {
495,889,871✔
4848
      bucketHisto[0] += 8;
495,151,317✔
4849
    } else {
4850
      bytes = (uint8_t*)word;
738,554✔
4851
      bucketHisto[bytes[0]]++;
738,554✔
4852
      bucketHisto[bytes[1]]++;
738,554✔
4853
      bucketHisto[bytes[2]]++;
738,554✔
4854
      bucketHisto[bytes[3]]++;
738,554✔
4855
      bucketHisto[bytes[4]]++;
738,554✔
4856
      bucketHisto[bytes[5]]++;
738,554✔
4857
      bucketHisto[bytes[6]]++;
738,554✔
4858
      bucketHisto[bytes[7]]++;
738,554✔
4859
    }
4860
    word++;
495,889,871✔
4861
  }
4862
}
245,856✔
4863
static double hllTau(double x) {
245,859✔
4864
  if (x == 0. || x == 1.) return 0.;
245,859!
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) {
245,877✔
4878
  if (x == 1.0) return INFINITY;
245,877✔
4879
  double zPrime;
4880
  double y = 1;
222,882✔
4881
  double z = x;
222,882✔
4882
  do {
4883
    x *= x;
4,383,853✔
4884
    zPrime = z;
4,383,853✔
4885
    z += x * y;
4,383,853✔
4886
    y += y;
4,383,853✔
4887
  } while (zPrime != z);
4,383,853✔
4888
  return z;
222,882✔
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) {
245,829✔
4894
  double  m = HLL_BUCKETS;
245,829✔
4895
  int32_t buckethisto[64] = {0};
245,829✔
4896
  hllBucketHisto(buckets, buckethisto);
245,829✔
4897

4898
  double z = m * hllTau((m - buckethisto[HLL_DATA_BITS + 1]) / (double)m);
245,861✔
4899
  for (int j = HLL_DATA_BITS; j >= 1; --j) {
12,534,887✔
4900
    z += buckethisto[j];
12,289,009✔
4901
    z *= 0.5;
12,289,009✔
4902
  }
4903

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

4907
  return (uint64_t)E;
245,878✔
4908
}
4909

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

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

4916
  int32_t type = pCol->info.type;
269,565✔
4917
  int32_t bytes = pCol->info.bytes;
269,565✔
4918

4919
  int32_t start = pInput->startRowIndex;
269,565✔
4920
  int32_t numOfRows = pInput->numOfRows;
269,565✔
4921

4922
  int32_t numOfElems = 0;
269,565✔
4923
  if (IS_NULL_TYPE(type)) {
269,565✔
4924
    goto _hll_over;
1,548✔
4925
  }
4926

4927
  for (int32_t i = start; i < numOfRows + start; ++i) {
4,813,955✔
4928
    if (pCol->hasNull && colDataIsNull_s(pCol, i)) {
5,979,253!
4929
      continue;
752,218✔
4930
    }
4931

4932
    numOfElems++;
3,795,741✔
4933

4934
    char* data = colDataGetData(pCol, i);
3,795,741!
4935
    if (IS_VAR_DATA_TYPE(type)) {
3,795,741!
4936
      bytes = varDataLen(data);
1,236,483✔
4937
      data = varDataVal(data);
1,236,483✔
4938
    }
4939

4940
    int32_t index = 0;
3,795,741✔
4941
    uint8_t count = hllCountNum(data, bytes, &index);
3,795,741✔
4942
    uint8_t oldcount = pInfo->buckets[index];
3,793,720✔
4943
    if (count > oldcount) {
3,793,720✔
4944
      pInfo->buckets[index] = count;
756,536✔
4945
    }
4946
  }
4947

4948
_hll_over:
265,996✔
4949
  pInfo->totalCount += numOfElems;
267,544✔
4950

4951
  if (pInfo->totalCount == 0 && !tsCountAlwaysReturnValue) {
267,544✔
4952
    SET_VAL(GET_RES_INFO(pCtx), 0, 1);
483✔
4953
  } else {
4954
    SET_VAL(GET_RES_INFO(pCtx), 1, 1);
267,061✔
4955
  }
4956

4957
  return TSDB_CODE_SUCCESS;
267,544✔
4958
}
4959

4960
static void hllTransferInfo(SHLLInfo* pInput, SHLLInfo* pOutput) {
11,622✔
4961
  for (int32_t k = 0; k < HLL_BUCKETS; ++k) {
186,610,884✔
4962
    if (pOutput->buckets[k] < pInput->buckets[k]) {
186,599,262✔
4963
      pOutput->buckets[k] = pInput->buckets[k];
105,429✔
4964
    }
4965
  }
4966
  pOutput->totalCount += pInput->totalCount;
11,622✔
4967
}
11,622✔
4968

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

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

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

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

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

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

4999
  return TSDB_CODE_SUCCESS;
11,553✔
5000
}
5001

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

5005
  SHLLInfo* pHllInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
245,831✔
5006
  pHllInfo->result = hllCountCnt(pHllInfo->buckets);
245,831✔
5007
  if (tsCountAlwaysReturnValue && pHllInfo->result == 0) {
245,882✔
5008
    pInfo->numOfRes = 1;
22,533✔
5009
  }
5010

5011
  return functionFinalize(pCtx, pBlock);
245,882✔
5012
}
5013

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

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

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

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

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

5059
static int8_t getStateOpType(char* opStr) {
7,881✔
5060
  int8_t opType;
5061
  if (strncasecmp(opStr, "LT", 2) == 0) {
7,881✔
5062
    opType = STATE_OPER_LT;
1,351✔
5063
  } else if (strncasecmp(opStr, "GT", 2) == 0) {
6,530✔
5064
    opType = STATE_OPER_GT;
4,190✔
5065
  } else if (strncasecmp(opStr, "LE", 2) == 0) {
2,340✔
5066
    opType = STATE_OPER_LE;
496✔
5067
  } else if (strncasecmp(opStr, "GE", 2) == 0) {
1,844✔
5068
    opType = STATE_OPER_GE;
502✔
5069
  } else if (strncasecmp(opStr, "NE", 2) == 0) {
1,342✔
5070
    opType = STATE_OPER_NE;
760✔
5071
  } else if (strncasecmp(opStr, "EQ", 2) == 0) {
582!
5072
    opType = STATE_OPER_EQ;
583✔
5073
  } else {
5074
    opType = STATE_OPER_INVALID;
×
5075
  }
5076

5077
  return opType;
7,881✔
5078
}
5079

5080
static bool checkStateOp(int8_t op, SColumnInfoData* pCol, int32_t index, SVariant param) {
494,420✔
5081
  char* data = colDataGetData(pCol, index);
494,420!
5082
  switch (pCol->info.type) {
494,420!
5083
    case TSDB_DATA_TYPE_TINYINT: {
140,759✔
5084
      int8_t v = *(int8_t*)data;
140,759✔
5085
      STATE_COMP(op, v, param);
140,759!
5086
      break;
45✔
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: {
21,056✔
5094
      int16_t v = *(int16_t*)data;
21,056✔
5095
      STATE_COMP(op, v, param);
21,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: {
4,768✔
5104
      int32_t v = *(int32_t*)data;
4,768✔
5105
      STATE_COMP(op, v, param);
4,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: {
61,584✔
5114
      int64_t v = *(int64_t*)data;
61,584✔
5115
      STATE_COMP(op, v, param);
61,584!
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: {
233,006✔
5124
      float v = *(float*)data;
233,006✔
5125
      STATE_COMP(op, v, param);
233,006!
5126
      break;
5✔
5127
    }
5128
    case TSDB_DATA_TYPE_DOUBLE: {
21,978✔
5129
      double v = *(double*)data;
21,978✔
5130
      STATE_COMP(op, v, param);
21,978!
5131
      break;
×
5132
    }
5133
    default: {
×
5134
      return false;
×
5135
    }
5136
  }
5137
  return false;
50✔
5138
}
5139

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

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

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

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

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

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

5165
    pInfo->isPrevTsSet = true;
604,127✔
5166
    numOfElems++;
604,127✔
5167

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

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

5182
    int64_t output = -1;
362,039✔
5183
    if (ret) {
362,039✔
5184
      output = ++pInfo->count;
207,786✔
5185
    } else {
5186
      pInfo->count = 0;
154,253✔
5187
    }
5188
    code = colDataSetVal(pOutput, pCtx->offset + numOfElems - 1, (char*)&output, false);
362,039✔
5189
    if (TSDB_CODE_SUCCESS != code) {
361,894!
5190
      return code;
×
5191
    }
5192

5193
    // handle selectivity
5194
    if (pCtx->subsidiaries.num > 0) {
361,894✔
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;
3,127✔
5203
  return TSDB_CODE_SUCCESS;
3,127✔
5204
}
5205

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

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

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

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

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

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

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

5237
    pInfo->isPrevTsSet = true;
281,293✔
5238
    numOfElems++;
281,293✔
5239

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

5252
    bool    ret = checkStateOp(op, pInputCol, i, pCtx->param[2].param);
134,401✔
5253
    int64_t output = -1;
134,401✔
5254
    if (ret) {
134,401✔
5255
      if (pInfo->durationStart == 0) {
99,307✔
5256
        output = 0;
15,460✔
5257
        pInfo->durationStart = tsList[i];
15,460✔
5258
      } else {
5259
        output = (tsList[i] - pInfo->durationStart) / timeUnit;
83,847✔
5260
      }
5261
    } else {
5262
      pInfo->durationStart = 0;
35,094✔
5263
    }
5264
    code = colDataSetVal(pOutput, pCtx->offset + numOfElems - 1, (char*)&output, false);
134,401✔
5265
    if (TSDB_CODE_SUCCESS != code) {
134,401!
5266
      return code;
×
5267
    }
5268

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

5282
bool getCsumFuncEnv(SFunctionNode* UNUSED_PARAM(pFunc), SFuncExecEnv* pEnv) {
4,995✔
5283
  pEnv->calcMemSize = sizeof(SSumRes);
4,995✔
5284
  return true;
4,995✔
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) {
861,701✔
5302
    if (pSumRes->isPrevTsSet == true && tsList[i] == pSumRes->prevTs) {
856,170✔
5303
      return TSDB_CODE_FUNC_DUP_TIMESTAMP;
18✔
5304
    } else {
5305
      pSumRes->prevTs = tsList[i];
856,152✔
5306
    }
5307
    pSumRes->isPrevTsSet = true;
856,152✔
5308

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

5315
    char* data = colDataGetData(pInputCol, i);
164,655!
5316
    if (IS_SIGNED_NUMERIC_TYPE(type)) {
310,202✔
5317
      int64_t v;
5318
      GET_TYPED_DATA(v, int64_t, type, data);
145,526!
5319
      pSumRes->isum += v;
145,526✔
5320
      code = colDataSetVal(pOutput, pos, (char*)&pSumRes->isum, false);
145,526✔
5321
      if (TSDB_CODE_SUCCESS != code) {
145,547!
5322
        return code;
×
5323
      }
5324
    } else if (IS_UNSIGNED_NUMERIC_TYPE(type)) {
19,639!
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)) {
18,619✔
5333
      double v;
5334
      GET_TYPED_DATA(v, double, type, data);
18,600!
5335
      pSumRes->dsum += v;
18,600✔
5336
      // check for overflow
5337
      if (isinf(pSumRes->dsum) || isnan(pSumRes->dsum)) {
18,600!
5338
        colDataSetNULL(pOutput, pos);
6!
5339
      } else {
5340
        code = colDataSetVal(pOutput, pos, (char*)&pSumRes->dsum, false);
18,594✔
5341
        if (TSDB_CODE_SUCCESS != code) {
18,594!
5342
          return code;
×
5343
        }
5344
      }
5345
    }
5346

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

5355
    numOfElems++;
164,676✔
5356
  }
5357

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

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

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

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

5386
  return TSDB_CODE_SUCCESS;
4,420✔
5387
}
5388

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

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

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

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

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

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

5422
    if (!pInfo->pointsMeet && (pInfo->pos < pInfo->numOfPoints - 1)) {
330,471✔
5423
      pInfo->points[pInfo->pos] = v;
328,582✔
5424
      pInfo->sum += v;
328,582✔
5425
    } else {
5426
      if (!pInfo->pointsMeet && (pInfo->pos == pInfo->numOfPoints - 1)) {
1,889!
5427
        pInfo->sum += v;
566✔
5428
        pInfo->pointsMeet = true;
566✔
5429
      } else {
5430
        pInfo->sum = pInfo->sum + v - pInfo->points[pInfo->pos];
1,323✔
5431
      }
5432

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

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

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

5456
    pInfo->pos++;
330,471✔
5457
    if (pInfo->pos == pInfo->numOfPoints) {
330,471✔
5458
      pInfo->pos = 0;
916✔
5459
    }
5460
  }
5461

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

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

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

5473
  return pInfo;
24,783✔
5474
}
5475

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

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

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

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

5505
  return TSDB_CODE_SUCCESS;
11,660✔
5506
}
5507

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

5512
static int32_t doReservoirSample(SqlFunctionCtx* pCtx, SSampleInfo* pInfo, char* data, int32_t index) {
424,593✔
5513
  pInfo->totalPoints++;
424,593✔
5514
  if (pInfo->numSampled < pInfo->samples) {
424,593✔
5515
    sampleAssignResult(pInfo, data, pInfo->numSampled);
344,612✔
5516
    if (pCtx->subsidiaries.num > 0) {
344,600✔
5517
      int32_t code = saveTupleData(pCtx, index, pCtx->pSrcBlock, &pInfo->tuplePos[pInfo->numSampled]);
6,246✔
5518
      if (code != TSDB_CODE_SUCCESS) {
6,270!
5519
        return code;
×
5520
      }
5521
    }
5522
    pInfo->numSampled++;
344,624✔
5523
  } else {
5524
    int32_t j = taosRand() % (pInfo->totalPoints);
79,981✔
5525
    if (j < pInfo->samples) {
79,984✔
5526
      sampleAssignResult(pInfo, data, j);
27,265✔
5527
      if (pCtx->subsidiaries.num > 0) {
27,265✔
5528
        int32_t code = updateTupleData(pCtx, index, pCtx->pSrcBlock, &pInfo->tuplePos[j]);
367✔
5529
        if (code != TSDB_CODE_SUCCESS) {
387!
5530
          return code;
×
5531
        }
5532
      }
5533
    }
5534
  }
5535

5536
  return TSDB_CODE_SUCCESS;
424,628✔
5537
}
5538

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

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

5545
  SColumnInfoData* pInputCol = pInput->pData[0];
13,126✔
5546
  for (int32_t i = pInput->startRowIndex; i < pInput->numOfRows + pInput->startRowIndex; i += 1) {
892,199✔
5547
    if (colDataIsNull_s(pInputCol, i)) {
1,754,224✔
5548
      continue;
454,470✔
5549
    }
5550

5551
    char*   data = colDataGetData(pInputCol, i);
422,642!
5552
    int32_t code = doReservoirSample(pCtx, pInfo, data, i);
422,642✔
5553
    if (code != TSDB_CODE_SUCCESS) {
424,603!
5554
      return code;
×
5555
    }
5556
  }
5557

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

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

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

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

5583
  int32_t currentRow = pBlock->info.rows;
11,659✔
5584
  if (pInfo->numSampled == 0) {
11,659✔
5585
    colDataSetNULL(pCol, currentRow);
2,629✔
5586
    code = setSelectivityValue(pCtx, pBlock, &pInfo->nullTuplePos, currentRow);
2,629✔
5587
    return code;
2,629✔
5588
  }
5589
  for (int32_t i = 0; i < pInfo->numSampled; ++i) {
353,703✔
5590
    code = colDataSetVal(pCol, currentRow + i, pInfo->data + i * pInfo->colBytes, false);
344,675✔
5591
    if (TSDB_CODE_SUCCESS != code) {
344,742!
5592
      return code;
×
5593
    }
5594
    code = setSelectivityValue(pCtx, pBlock, &pInfo->tuplePos[i], currentRow + i);
344,742✔
5595
    if (TSDB_CODE_SUCCESS != code) {
344,673!
5596
      return code;
×
5597
    }
5598
  }
5599

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

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

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

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

5878
static void modeFunctionCleanup(SModeInfo* pInfo) {
5,172✔
5879
  taosHashCleanup(pInfo->pHash);
5,172✔
5880
  pInfo->pHash = NULL;
5,171✔
5881
  taosMemoryFreeClear(pInfo->buf);
5,171!
5882
}
5,171✔
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) {
465,737✔
5892
  if (IS_VAR_DATA_TYPE(pInfo->colType)) {
465,737!
5893
    if (pInfo->colType == TSDB_DATA_TYPE_JSON) {
72,017!
5894
      (void)memcpy(pInfo->buf, data, getJsonValueLen(data));
×
5895
    } else {
5896
      (void)memcpy(pInfo->buf, data, varDataTLen(data));
72,017✔
5897
    }
5898
  } else {
5899
    (void)memcpy(pInfo->buf, data, pInfo->colBytes);
393,720✔
5900
  }
5901

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

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

5918
  SModeItem* pHashItem = (SModeItem*)taosHashGet(pInfo->pHash, data, hashKeyBytes);
503,378✔
5919
  if (pHashItem == NULL) {
502,065✔
5920
    int32_t   size = sizeof(SModeItem);
465,533✔
5921
    SModeItem item = {0};
465,533✔
5922

5923
    item.count += 1;
465,533✔
5924
    code = saveModeTupleData(pCtx, data, pInfo, &item.dataPos);
465,533✔
5925
    if (code != TSDB_CODE_SUCCESS) {
464,982!
5926
      return code;
×
5927
    }
5928

5929
    if (pCtx->subsidiaries.num > 0) {
464,982✔
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));
464,982✔
5937
    if (code != TSDB_CODE_SUCCESS) {
467,054!
5938
      return code;
×
5939
    }
5940
  } else {
5941
    pHashItem->count += 1;
36,532✔
5942
    if (pCtx->subsidiaries.num > 0) {
36,532✔
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;
503,586✔
5951
}
5952

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

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

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

5962
  int32_t numOfElems = 0;
6,202✔
5963
  int32_t startOffset = pCtx->offset;
6,202✔
5964
  for (int32_t i = pInput->startRowIndex; i < pInput->numOfRows + pInput->startRowIndex; ++i) {
930,693✔
5965
    if (colDataIsNull_s(pInputCol, i)) {
1,848,946✔
5966
      continue;
421,245✔
5967
    }
5968
    numOfElems++;
503,228✔
5969

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

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

5989
  return TSDB_CODE_SUCCESS;
6,220✔
5990
}
5991

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

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

6007
  void* pIter = taosHashIterate(pInfo->pHash, NULL);
5,172✔
6008
  while (pIter != NULL) {
472,465✔
6009
    SModeItem* pItem = (SModeItem*)pIter;
467,293✔
6010
    if (pItem->count >= maxCount) {
467,293✔
6011
      maxCount = pItem->count;
457,649✔
6012
      resDataPos = pItem->dataPos;
457,649✔
6013
      resTuplePos = pItem->tuplePos;
457,649✔
6014
    }
6015

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

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

6041
  modeFunctionCleanup(pInfo);
5,172✔
6042

6043
  return code;
5,171✔
6044
}
6045

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

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

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

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

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

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

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

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

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

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

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

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

6114
      pInfo->dOutput += twa_get_area(pCtx->start, *last);
13,257✔
6115
      pInfo->win.skey = pCtx->start.key;
13,257✔
6116
      pInfo->numOfElems++;
13,257✔
6117
      break;
13,257✔
6118
    }
6119
  } else if (pInfo->p.key == INT64_MIN) {
26,732✔
6120
    while (1) {
6121
      code = funcInputGetNextRow(pCtx, &row, &result);
149,363✔
6122
      if (TSDB_CODE_SUCCESS != code) {
149,362!
6123
        return code;
×
6124
      }
6125
      if (!result) {
149,362✔
6126
        break;
10,881✔
6127
      }
6128
      if (row.isDataNull) {
138,481✔
6129
        continue;
122,993✔
6130
      }
6131

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

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

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

6142
  SPoint1 st = {0};
39,990✔
6143

6144
  // calculate the value of
6145
  while (1) {
6146
    code = funcInputGetNextRow(pCtx, &row, &result);
471,463✔
6147
    if (TSDB_CODE_SUCCESS != code) {
471,478!
6148
      return code;
×
6149
    }
6150
    if (!result) {
471,478✔
6151
      break;
39,994✔
6152
    }
6153
    if (row.isDataNull) {
431,484✔
6154
      continue;
378✔
6155
    }
6156
    pInfo->numOfElems++;
431,106✔
6157
    switch (pInputCol->info.type) {
431,106✔
6158
      case TSDB_DATA_TYPE_TINYINT: {
54,044✔
6159
        INIT_INTP_POINT(st, row.ts, *(int8_t*)row.pData);
54,044✔
6160
        break;
54,044✔
6161
      }
6162
      case TSDB_DATA_TYPE_SMALLINT: {
54,467✔
6163
        INIT_INTP_POINT(st, row.ts, *(int16_t*)row.pData);
54,467✔
6164
        break;
54,467✔
6165
      }
6166
      case TSDB_DATA_TYPE_INT: {
69,378✔
6167
        INIT_INTP_POINT(st, row.ts, *(int32_t*)row.pData);
69,378✔
6168
        break;
69,378✔
6169
      }
6170
      case TSDB_DATA_TYPE_BIGINT: {
61,879✔
6171
        INIT_INTP_POINT(st, row.ts, *(int64_t*)row.pData);
61,879✔
6172
        break;
61,879✔
6173
      }
6174
      case TSDB_DATA_TYPE_FLOAT: {
27,959✔
6175
        INIT_INTP_POINT(st, row.ts, *(float_t*)row.pData);
27,959✔
6176
        break;
27,959✔
6177
      }
6178
      case TSDB_DATA_TYPE_DOUBLE: {
50,421✔
6179
        INIT_INTP_POINT(st, row.ts, *(double*)row.pData);
50,421✔
6180
        break;
50,421✔
6181
      }
6182
      case TSDB_DATA_TYPE_UTINYINT: {
29,320✔
6183
        INIT_INTP_POINT(st, row.ts, *(uint8_t*)row.pData);
29,320✔
6184
        break;
29,320✔
6185
      }
6186
      case TSDB_DATA_TYPE_USMALLINT: {
28,905✔
6187
        INIT_INTP_POINT(st, row.ts, *(uint16_t*)row.pData);
28,905✔
6188
        break;
28,905✔
6189
      }
6190
      case TSDB_DATA_TYPE_UINT: {
31,142✔
6191
        INIT_INTP_POINT(st, row.ts, *(uint32_t*)row.pData);
31,142✔
6192
        break;
31,142✔
6193
      }
6194
      case TSDB_DATA_TYPE_UBIGINT: {
23,483✔
6195
        INIT_INTP_POINT(st, row.ts, *(uint64_t*)row.pData);
23,483✔
6196
        break;
23,483✔
6197
      }
6198
      default: {
108✔
6199
        return TSDB_CODE_FUNC_FUNTION_PARA_TYPE;
108✔
6200
      }
6201
    }
6202
    if (pInfo->p.key == st.key) {
430,998!
6203
      return TSDB_CODE_FUNC_DUP_TIMESTAMP;
×
6204
    }
6205

6206
    pInfo->dOutput += twa_get_area(pInfo->p, st);
430,998✔
6207
    pInfo->p = st;
431,095✔
6208
  }
6209

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

6217
  pInfo->win.ekey = pInfo->p.key;
39,994✔
6218

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

6239
  STwaInfo* pInfo = (STwaInfo*)GET_ROWCELL_INTERBUF(pResInfo);
39,585✔
6240
  if (pInfo->numOfElems == 0) {
39,585✔
6241
    pResInfo->numOfRes = 0;
10,729✔
6242
  } else {
6243
    if (pInfo->win.ekey == pInfo->win.skey) {
28,856✔
6244
      pInfo->dTwaRes = pInfo->p.val;
10,410✔
6245
    } else if (pInfo->win.ekey == INT64_MAX || pInfo->win.skey == INT64_MIN) {  // no data in timewindow
18,446!
6246
      pInfo->dTwaRes = 0;
2✔
6247
    } else {
6248
      pInfo->dTwaRes = pInfo->dOutput / (pInfo->win.ekey - pInfo->win.skey);
18,444✔
6249
    }
6250

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

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

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

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

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

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

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

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

6648
  funcInputUpdate(pCtx);
762✔
6649

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

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

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

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

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

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

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

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

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

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

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

6764
  pResInfo->numOfRes = numOfElems;
762✔
6765

6766
  return TSDB_CODE_SUCCESS;
762✔
6767
}
6768

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

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

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

6785
  SRateInfo* pInfo = GET_ROWCELL_INTERBUF(pResInfo);
25,757✔
6786

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

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

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

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

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

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

6857
  SColumnInfoData* pOutput = (SColumnInfoData*)pCtx->pOutput;
26,152✔
6858

6859
  funcInputUpdate(pCtx);
26,152✔
6860

6861
  initializeRateInfo(pCtx, pRateInfo, false);
26,152✔
6862

6863
  int32_t       numOfElems = 0;
26,152✔
6864
  int32_t       type = pInputCol->info.type;
26,152✔
6865
  SFuncInputRow row = {0};
26,152✔
6866
  bool          result = false;
26,152✔
6867
  while (1) {
239,882✔
6868
    code = funcInputGetNextRow(pCtx, &row, &result);
266,034✔
6869
    if (TSDB_CODE_SUCCESS != code) {
266,032!
6870
      return code;
×
6871
    }
6872
    if (!result) {
266,032✔
6873
      break;
26,153✔
6874
    }
6875
    if (row.isDataNull) {
239,879✔
6876
      continue;
113,008✔
6877
    }
6878

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

6883
    if (INT64_MIN == pRateInfo->lastKey) {
126,871✔
6884
      doSaveRateInfo(pRateInfo, false, row.ts, row.pPk, v);
13,811✔
6885
      pRateInfo->hasResult = 1;
13,811✔
6886
      continue;
13,811✔
6887
    }
6888

6889
    if (row.ts > pRateInfo->lastKey) {
113,060✔
6890
      if ((INT64_MIN == pRateInfo->firstKey) || pRateInfo->lastKey > pRateInfo->firstKey) {
111,285!
6891
        doSaveRateInfo(pRateInfo, true, pRateInfo->lastKey, pRateInfo->lastPk, pRateInfo->lastValue);
111,285✔
6892
      }
6893
      doSaveRateInfo(pRateInfo, false, row.ts, row.pPk, v);
111,285✔
6894
      continue;
111,283✔
6895
    } else if (row.ts == pRateInfo->lastKey) {
1,775!
6896
      return TSDB_CODE_FUNC_DUP_TIMESTAMP;
×
6897
    }
6898

6899
    if ((INT64_MIN == pRateInfo->firstKey) || row.ts > pRateInfo->firstKey) {
1,775!
UNCOV
6900
      doSaveRateInfo(pRateInfo, true, row.ts, row.pPk, v);
×
6901
    } else if (row.ts == pRateInfo->firstKey) {
1,776!
6902
      return TSDB_CODE_FUNC_DUP_TIMESTAMP;
×
6903
    }
6904
  }
6905

6906
  numOfElems++;
26,153✔
6907

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

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

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

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

6931
  return (duration > 0) ? ((double)diff) / (duration / tickPerSec) : 0.0;
1,010!
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);
62✔
6937
    if (isFirstKey) {
62✔
6938
      doSaveRateInfo(pOutput, false, pInput->firstKey, pInput->firstPk, pInput->firstValue);
26✔
6939
    } else {
6940
      doSaveRateInfo(pOutput, false, pInput->lastKey, pInput->lastPk, pInput->lastValue);
36✔
6941
    }
6942
  } else if ((inputKey < pOutput->lastKey) && (inputKey > pOutput->firstKey)) {
112!
6943
    if (isFirstKey) {
16✔
6944
      doSaveRateInfo(pOutput, true, pInput->firstKey, pInput->firstPk, pInput->firstValue);
8✔
6945
    } else {
6946
      doSaveRateInfo(pOutput, true, pInput->lastKey, pInput->lastPk, pInput->lastValue);
8✔
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) {
185✔
7014
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
185✔
7015
  SRateInfo*           pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
185✔
7016
  int32_t              resultBytes = getIrateInfoSize(pInfo->pkBytes);
185✔
7017
  char*                res = taosMemoryCalloc(resultBytes + VARSTR_HEADER_SIZE, sizeof(char));
185!
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);
185!
7035
  return code;
186✔
7036
}
7037

7038
int32_t irateFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
25,571✔
7039
  int32_t          slotId = pCtx->pExpr->base.resSchema.slotId;
25,571✔
7040
  SColumnInfoData* pCol = taosArrayGet(pBlock->pDataBlock, slotId);
25,571✔
7041
  if (NULL == pCol) {
25,571!
7042
    return TSDB_CODE_OUT_OF_RANGE;
×
7043
  }
7044

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

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

7052
  return code;
25,571✔
7053
}
7054

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

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

7062
  int32_t startIndex = pInput->startRowIndex;
81,409,892✔
7063

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

7069
  if (pInputCol->pData == NULL || colDataIsNull_s(pInputCol, startIndex)) {
141,730,779✔
7070
    pInfo->isNull = true;
1,489,195✔
7071
    pInfo->hasResult = true;
1,489,195✔
7072
    goto _group_value_over;
1,489,195✔
7073
  }
7074

7075
  char* data = colDataGetData(pInputCol, startIndex);
69,472,422!
7076
  if (IS_VAR_DATA_TYPE(pInputCol->info.type)) {
69,472,422!
7077
    (void)memcpy(pInfo->data, data,
49,688,992✔
7078
                 (pInputCol->info.type == TSDB_DATA_TYPE_JSON) ? getJsonValueLen(data) : varDataTLen(data));
49,688,992✔
7079
  } else {
7080
    (void)memcpy(pInfo->data, data, pInputCol->info.bytes);
19,783,430✔
7081
  }
7082
  pInfo->hasResult = true;
69,472,422✔
7083

7084
_group_value_over:
81,409,892✔
7085

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

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

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

7100
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
69,771,107✔
7101

7102
  SGroupKeyInfo* pInfo = GET_ROWCELL_INTERBUF(pResInfo);
69,771,107✔
7103

7104
  if (pInfo->hasResult) {
69,771,107!
7105
    int32_t currentRow = pBlock->info.rows;
69,802,523✔
7106
    for (; currentRow < pBlock->info.rows + pResInfo->numOfRes; ++currentRow) {
140,271,358✔
7107
      code = colDataSetVal(pCol, currentRow, pInfo->data, pInfo->isNull ? true : false);
69,811,808✔
7108
      if (TSDB_CODE_SUCCESS != code) {
70,468,835!
7109
        return code;
×
7110
      }
7111
    }
7112
  } else {
7113
    pResInfo->numOfRes = 0;
×
7114
  }
7115

7116
  return code;
70,428,134✔
7117
}
7118

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

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

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

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

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

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

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

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