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

taosdata / TDengine / #3585

20 Jan 2025 09:22AM UTC coverage: 63.647% (-0.1%) from 63.756%
#3585

push

travis-ci

web-flow
Merge pull request #29603 from taosdata/enh/3.0/TD-32588

enh:[TD-32588]refactor stmt-async-bind loop usleep to Producer Consumer Model

140935 of 284561 branches covered (49.53%)

Branch coverage included in aggregate %.

219502 of 281745 relevant lines covered (77.91%)

18611836.92 hits per line

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

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

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

31
bool ignoreNegative(int8_t ignoreOption) { return (ignoreOption & 0x1) == 0x1; }
1,246,856,710✔
32
bool ignoreNull(int8_t ignoreOption) { return (ignoreOption & 0x2) == 0x2; }
1,519,504✔
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) {
18,297,670✔
194
  SFuncInputRowIter* pIter = &pCtx->rowIter;
18,297,670✔
195

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

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

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

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

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

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

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

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

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

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

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

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

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

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

382
bool funcInputGetNextRowNoPk(SFuncInputRowIter* pIter, SFuncInputRow* pRow) {
1,307,347,634✔
383
  if (pIter->rowIndex <= pIter->inputEndIndex) {
1,307,347,634✔
384
    setInputRowInfo(pRow, pIter, pIter->rowIndex, false);
1,289,236,415✔
385
    ++pIter->rowIndex;
1,289,119,744✔
386
    return true;
1,289,119,744✔
387
  } else {
388
    return false;
18,111,219✔
389
  }
390
}
391

392
int32_t funcInputGetNextRow(SqlFunctionCtx* pCtx, SFuncInputRow* pRow, bool* res) {
1,307,431,051✔
393
  SFuncInputRowIter* pIter = &pCtx->rowIter;
1,307,431,051✔
394
  if (pCtx->hasPrimaryKey) {
1,307,431,051✔
395
    if (pCtx->order == TSDB_ORDER_ASC) {
330!
396
      *res = funcInputGetNextRowAscPk(pIter, pRow);
330✔
397
      return TSDB_CODE_SUCCESS;
330✔
398
    } else {
399
      return funcInputGetNextRowDescPk(pIter, pRow, res);
×
400
    }
401
  } else {
402
    *res = funcInputGetNextRowNoPk(pIter, pRow);
1,307,430,721✔
403
    return TSDB_CODE_SUCCESS;
1,307,181,292✔
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) {
24,815,400✔
411
  if (pCtx->subsidiaries.num <= 0) {
24,815,400!
412
    return TSDB_CODE_SUCCESS;
×
413
  }
414

415
  for (int32_t j = 0; j < pCtx->subsidiaries.num; ++j) {
70,189,640✔
416
    SqlFunctionCtx* pc = pCtx->subsidiaries.pCtx[j];
45,374,240✔
417

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

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

427
    char* pData = colDataGetData(pSrcCol, rowIndex);
45,374,240!
428

429
    // append to dest col
430
    int32_t dstSlotId = pc->pExpr->base.resSchema.slotId;
45,374,240✔
431

432
    SColumnInfoData* pDstCol = taosArrayGet(pCtx->pDstBlock->pDataBlock, dstSlotId);
45,374,240✔
433
    if (NULL == pDstCol) {
45,374,240!
434
      return TSDB_CODE_OUT_OF_RANGE;
×
435
    }
436
    if (colDataIsNull_s(pSrcCol, rowIndex) == true) {
90,748,480✔
437
      colDataSetNULL(pDstCol, pos);
2,064,031✔
438
    } else {
439
      int32_t code = colDataSetVal(pDstCol, pos, pData, false);
43,310,209✔
440
      if (TSDB_CODE_SUCCESS != code) {
43,310,209!
441
        return code;
×
442
      }
443
    }
444
  }
445
  return TSDB_CODE_SUCCESS;
24,815,400✔
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) {
700,453,966✔
454
  if (pResultInfo->initialized) {
700,453,966✔
455
    return TSDB_CODE_SUCCESS;  // already initialized
167,591✔
456
  }
457

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

462
  initResultRowEntry(pResultInfo, pCtx->resDataInfo.interBufSize);
700,286,375✔
463
  return TSDB_CODE_SUCCESS;
700,286,375✔
464
}
465

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

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

479
  return code;
176,266,511✔
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) {
198,945✔
513
  SNode* pParam = nodesListGetNode(pFunc->pParameterList, 0);
198,945✔
514
  if (QUERY_NODE_COLUMN == nodeType(pParam) && PRIMARYKEY_TIMESTAMP_COL_ID == ((SColumnNode*)pParam)->colId) {
198,976!
515
    return FUNC_DATA_REQUIRED_NOT_LOAD;
146,456✔
516
  }
517
  return FUNC_DATA_REQUIRED_SMA_LOAD;
52,520✔
518
}
519

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

525
static int64_t getNumOfElems(SqlFunctionCtx* pCtx) {
113,988,310✔
526
  int64_t numOfElem = 0;
113,988,310✔
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;
113,988,310✔
534
  SColumnInfoData*      pInputCol = pInput->pData[0];
113,988,310✔
535
  if (1 == pInput->numOfRows && pInput->blankFill) {
113,988,310✔
536
    return 0;
447,195✔
537
  }
538
  if (pInput->colDataSMAIsSet && pInput->totalRows == pInput->numOfRows) {
113,541,115!
539
    numOfElem = pInput->numOfRows - pInput->pColumnDataAgg[0]->numOfNull;
2,114✔
540
  } else {
541
    if (pInputCol->hasNull) {
113,539,001✔
542
      for (int32_t i = pInput->startRowIndex; i < pInput->startRowIndex + pInput->numOfRows; ++i) {
333,021,409✔
543
        if (colDataIsNull(pInputCol, pInput->totalRows, i, NULL)) {
602,605,290!
544
          continue;
1,836,566✔
545
        }
546
        numOfElem += 1;
299,466,079✔
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;
81,820,237✔
552
    }
553
  }
554
  return numOfElem;
113,541,115✔
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) {
114,149,250✔
562
  int64_t numOfElem = 0;
114,149,250✔
563

564
  SResultRowEntryInfo*  pResInfo = GET_RES_INFO(pCtx);
114,149,250✔
565
  SInputColumnInfoData* pInput = &pCtx->input;
114,149,250✔
566

567
  int32_t type = pInput->pData[0]->info.type;
114,149,250✔
568

569
  char* buf = GET_ROWCELL_INTERBUF(pResInfo);
114,149,250✔
570
  if (IS_NULL_TYPE(type)) {
114,149,250✔
571
    // select count(NULL) returns 0
572
    numOfElem = 1;
136,808✔
573
    *((int64_t*)buf) += 0;
136,808✔
574
  } else {
575
    numOfElem = getNumOfElems(pCtx);
114,012,442✔
576
    *((int64_t*)buf) += numOfElem;
113,644,020✔
577
  }
578

579
  if (tsCountAlwaysReturnValue) {
113,780,828!
580
    pResInfo->numOfRes = 1;
113,851,809✔
581
  } else {
582
    SET_VAL(pResInfo, *((int64_t*)buf), 1);
×
583
  }
584

585
  return TSDB_CODE_SUCCESS;
113,780,828✔
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) {
84,593,310✔
614
  int32_t numOfElem = 0;
84,593,310✔
615

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

621
  SSumRes* pSumRes = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
84,593,310✔
622
  pSumRes->type = type;
84,593,310✔
623

624
  if (IS_NULL_TYPE(type)) {
84,593,310✔
625
    numOfElem = 0;
225✔
626
    goto _sum_over;
225✔
627
  }
628

629
  if (pInput->colDataSMAIsSet) {
84,593,085✔
630
    numOfElem = pInput->numOfRows - pAgg->numOfNull;
428✔
631

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

642
    int32_t start = pInput->startRowIndex;
84,592,657✔
643
    int32_t numOfRows = pInput->numOfRows;
84,592,657✔
644

645
    if (IS_SIGNED_NUMERIC_TYPE(type) || type == TSDB_DATA_TYPE_BOOL) {
84,592,657!
646
      if (type == TSDB_DATA_TYPE_TINYINT || type == TSDB_DATA_TYPE_BOOL) {
83,745,441!
647
        LIST_ADD_N(pSumRes->isum, pCol, start, numOfRows, int8_t, numOfElem);
1,475,330✔
648
      } else if (type == TSDB_DATA_TYPE_SMALLINT) {
83,404,882✔
649
        LIST_ADD_N(pSumRes->isum, pCol, start, numOfRows, int16_t, numOfElem);
658,751✔
650
      } else if (type == TSDB_DATA_TYPE_INT) {
83,356,848✔
651
        LIST_ADD_N(pSumRes->isum, pCol, start, numOfRows, int32_t, numOfElem);
327,389,652✔
652
      } else if (type == TSDB_DATA_TYPE_BIGINT) {
23,126,378✔
653
        LIST_ADD_N(pSumRes->isum, pCol, start, numOfRows, int64_t, numOfElem);
82,874,760✔
654
      }
655
    } else if (IS_UNSIGNED_NUMERIC_TYPE(type)) {
847,216!
656
      if (type == TSDB_DATA_TYPE_UTINYINT) {
106✔
657
        LIST_ADD_N(pSumRes->usum, pCol, start, numOfRows, uint8_t, numOfElem);
50,015!
658
      } else if (type == TSDB_DATA_TYPE_USMALLINT) {
91✔
659
        LIST_ADD_N(pSumRes->usum, pCol, start, numOfRows, uint16_t, numOfElem);
50,023✔
660
      } else if (type == TSDB_DATA_TYPE_UINT) {
75✔
661
        LIST_ADD_N(pSumRes->usum, pCol, start, numOfRows, uint32_t, numOfElem);
50,015!
662
      } else if (type == TSDB_DATA_TYPE_UBIGINT) {
60!
663
        LIST_ADD_N(pSumRes->usum, pCol, start, numOfRows, uint64_t, numOfElem);
50,600✔
664
      }
665
    } else if (type == TSDB_DATA_TYPE_DOUBLE) {
847,110✔
666
      LIST_ADD_N(pSumRes->dsum, pCol, start, numOfRows, double, numOfElem);
1,994,485✔
667
    } else if (type == TSDB_DATA_TYPE_FLOAT) {
762,720✔
668
      LIST_ADD_N(pSumRes->dsum, pCol, start, numOfRows, float, numOfElem);
1,695,967✔
669
    }
670
  }
671

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

677
_sum_over:
84,984,555✔
678
  if (numOfElem == 0) {
84,593,310✔
679
    if (tsCountAlwaysReturnValue && pCtx->pExpr->pExpr->_function.pFunctNode->hasOriginalFunc &&
93,423✔
680
        fmIsCountLikeFunc(pCtx->pExpr->pExpr->_function.pFunctNode->originalFuncId)) {
11,310✔
681
      numOfElem = 1;
31✔
682
    }
683
  }
684
  // data in the check operation are all null, not output
685
  SET_VAL(GET_RES_INFO(pCtx), numOfElem, 1);
84,593,310✔
686
  return TSDB_CODE_SUCCESS;
84,593,310✔
687
}
688

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

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

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

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

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

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

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

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

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

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

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

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

774
static bool funcNotSupportStringSma(SFunctionNode* pFunc) {
171,948✔
775
  SNode* pParam;
776
  switch (pFunc->funcType) {
171,948✔
777
    case FUNCTION_TYPE_MAX:
157,936✔
778
    case FUNCTION_TYPE_MIN:
779
    case FUNCTION_TYPE_SUM:
780
    case FUNCTION_TYPE_AVG:
781
    case FUNCTION_TYPE_AVG_PARTIAL:
782
    case FUNCTION_TYPE_PERCENTILE:
783
    case FUNCTION_TYPE_SPREAD:
784
    case FUNCTION_TYPE_SPREAD_PARTIAL:
785
    case FUNCTION_TYPE_SPREAD_MERGE:
786
    case FUNCTION_TYPE_TWA:
787
      pParam = nodesListGetNode(pFunc->pParameterList, 0);
157,936✔
788
      if (pParam && nodesIsExprNode(pParam) && (IS_VAR_DATA_TYPE(((SExprNode*)pParam)->resType.type))) {
157,936!
789
        return true;
86✔
790
      }
791
      break;
157,850✔
792
    default:
14,012✔
793
      break;
14,012✔
794
  }
795
  return false;
171,862✔
796
}
797

798
EFuncDataRequired statisDataRequired(SFunctionNode* pFunc, STimeWindow* pTimeWindow) {
171,948✔
799
  if(funcNotSupportStringSma(pFunc)) {
171,948✔
800
    return FUNC_DATA_REQUIRED_DATA_LOAD;
86✔
801
  }
802
  return FUNC_DATA_REQUIRED_SMA_LOAD;
171,862✔
803
}
804

805
int32_t minmaxFunctionSetup(SqlFunctionCtx* pCtx, SResultRowEntryInfo* pResultInfo) {
55,663,197✔
806
  if (pResultInfo->initialized) {
55,663,197!
807
    return TSDB_CODE_SUCCESS;
×
808
  }
809
  if (TSDB_CODE_SUCCESS != functionSetup(pCtx, pResultInfo)) {
55,663,197!
810
    return TSDB_CODE_FUNC_SETUP_ERROR;  // not initialized since it has been initialized
×
811
  }
812

813
  SMinmaxResInfo* buf = GET_ROWCELL_INTERBUF(pResultInfo);
55,685,458✔
814
  buf->assign = false;
55,685,458✔
815
  buf->tuplePos.pageId = -1;
55,685,458✔
816

817
  buf->nullTupleSaved = false;
55,685,458✔
818
  buf->nullTuplePos.pageId = -1;
55,685,458✔
819
  buf->str = NULL;
55,685,458✔
820
  return TSDB_CODE_SUCCESS;
55,685,458✔
821
}
822

823
bool getMinmaxFuncEnv(SFunctionNode* UNUSED_PARAM(pFunc), SFuncExecEnv* pEnv) {
411,075✔
824
  pEnv->calcMemSize = sizeof(SMinmaxResInfo);
411,075✔
825
  return true;
411,075✔
826
}
827

828
int32_t minFunction(SqlFunctionCtx* pCtx) {
28,296,142✔
829
  int32_t numOfElems = 0;
28,296,142✔
830
  int32_t code = doMinMaxHelper(pCtx, 1, &numOfElems);
28,296,142✔
831
  if (code != TSDB_CODE_SUCCESS) {
28,440,011!
832
    return code;
×
833
  }
834
  SET_VAL(GET_RES_INFO(pCtx), numOfElems, 1);
28,440,011✔
835
  return TSDB_CODE_SUCCESS;
28,440,011✔
836
}
837

838
int32_t maxFunction(SqlFunctionCtx* pCtx) {
31,781,825✔
839
  int32_t numOfElems = 0;
31,781,825✔
840
  int32_t code = doMinMaxHelper(pCtx, 0, &numOfElems);
31,781,825✔
841
  if (code != TSDB_CODE_SUCCESS) {
31,908,920!
842
    return code;
×
843
  }
844
  SET_VAL(GET_RES_INFO(pCtx), numOfElems, 1);
31,908,920✔
845
  return TSDB_CODE_SUCCESS;
31,908,920✔
846
}
847

848
static int32_t setNullSelectivityValue(SqlFunctionCtx* pCtx, SSDataBlock* pBlock, int32_t rowIndex);
849
static int32_t setSelectivityValue(SqlFunctionCtx* pCtx, SSDataBlock* pBlock, const STuplePos* pTuplePos,
850
                                   int32_t rowIndex);
851

852
int32_t minmaxFunctionFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
53,613,285✔
853
  int32_t code = TSDB_CODE_SUCCESS;
53,613,285✔
854

855
  SResultRowEntryInfo* pEntryInfo = GET_RES_INFO(pCtx);
53,613,285✔
856
  SMinmaxResInfo*      pRes = GET_ROWCELL_INTERBUF(pEntryInfo);
53,613,285✔
857

858
  int32_t slotId = pCtx->pExpr->base.resSchema.slotId;
53,613,285✔
859
  int32_t currentRow = pBlock->info.rows;
53,613,285✔
860

861
  SColumnInfoData* pCol = taosArrayGet(pBlock->pDataBlock, slotId);
53,613,285✔
862
  if (NULL == pCol) {
53,620,945!
863
    return TSDB_CODE_OUT_OF_RANGE;
×
864
  }
865
  pEntryInfo->isNullRes = (pEntryInfo->numOfRes == 0) ? 1 : 0;
53,620,945✔
866

867
  // NOTE: do nothing change it, for performance issue
868
  if (!pEntryInfo->isNullRes) {
53,620,945✔
869
    switch (pCol->info.type) {
46,544,079!
870
      case TSDB_DATA_TYPE_UBIGINT:
14,730,442✔
871
      case TSDB_DATA_TYPE_BIGINT:
872
        ((int64_t*)pCol->pData)[currentRow] = pRes->v;
14,730,442✔
873
        break;
14,730,442✔
874
      case TSDB_DATA_TYPE_UINT:
21,598,180✔
875
      case TSDB_DATA_TYPE_INT:
876
        colDataSetInt32(pCol, currentRow, (int32_t*)&pRes->v);
21,598,180✔
877
        break;
21,598,180✔
878
      case TSDB_DATA_TYPE_USMALLINT:
229,157✔
879
      case TSDB_DATA_TYPE_SMALLINT:
880
        colDataSetInt16(pCol, currentRow, (int16_t*)&pRes->v);
229,157✔
881
        break;
229,157✔
882
      case TSDB_DATA_TYPE_BOOL:
218,045✔
883
      case TSDB_DATA_TYPE_UTINYINT:
884
      case TSDB_DATA_TYPE_TINYINT:
885
        colDataSetInt8(pCol, currentRow, (int8_t*)&pRes->v);
218,045✔
886
        break;
218,045✔
887
      case TSDB_DATA_TYPE_DOUBLE:
215,180✔
888
        colDataSetDouble(pCol, currentRow, (double*)&pRes->v);
215,180✔
889
        break;
215,180✔
890
      case TSDB_DATA_TYPE_FLOAT: {
7,106,861✔
891
        float v = GET_FLOAT_VAL(&pRes->v);
7,106,861✔
892
        colDataSetFloat(pCol, currentRow, &v);
7,106,861✔
893
        break;
7,106,861✔
894
      }
895
      case TSDB_DATA_TYPE_VARBINARY:
2,487,472✔
896
      case TSDB_DATA_TYPE_VARCHAR:
897
      case TSDB_DATA_TYPE_NCHAR: {
898
        code = colDataSetVal(pCol, currentRow, pRes->str, false);
2,487,472✔
899
        if (TSDB_CODE_SUCCESS != code) {
2,487,472!
900
          return code;
×
901
        }
902
        break;
2,487,472✔
903
      }
904
    }
905
  } else {
906
    colDataSetNULL(pCol, currentRow);
7,076,866!
907
  }
908

909
  taosMemoryFreeClear(pRes->str);
53,620,945!
910
  if (pCtx->subsidiaries.num > 0) {
53,620,945✔
911
    if (pEntryInfo->numOfRes > 0) {
12,651,882✔
912
      code = setSelectivityValue(pCtx, pBlock, &pRes->tuplePos, currentRow);
12,649,089✔
913
    } else {
914
      code = setSelectivityValue(pCtx, pBlock, &pRes->nullTuplePos, currentRow);
2,793✔
915
    }
916
  }
917

918
  return code;
53,632,434✔
919
}
920

921
#ifdef BUILD_NO_CALL
922
int32_t setNullSelectivityValue(SqlFunctionCtx* pCtx, SSDataBlock* pBlock, int32_t rowIndex) {
923
  if (pCtx->subsidiaries.num <= 0) {
924
    return TSDB_CODE_SUCCESS;
925
  }
926

927
  for (int32_t j = 0; j < pCtx->subsidiaries.num; ++j) {
928
    SqlFunctionCtx* pc = pCtx->subsidiaries.pCtx[j];
929
    int32_t         dstSlotId = pc->pExpr->base.resSchema.slotId;
930

931
    SColumnInfoData* pDstCol = taosArrayGet(pBlock->pDataBlock, dstSlotId);
932
    colDataSetNULL(pDstCol, rowIndex);
933
  }
934

935
  return TSDB_CODE_SUCCESS;
936
}
937
#endif
938

939
int32_t setSelectivityValue(SqlFunctionCtx* pCtx, SSDataBlock* pBlock, const STuplePos* pTuplePos, int32_t rowIndex) {
271,165,112✔
940
  if (pCtx->subsidiaries.num <= 0) {
271,165,112✔
941
    return TSDB_CODE_SUCCESS;
143,419,609✔
942
  }
943

944
  if ((pCtx->saveHandle.pBuf != NULL && pTuplePos->pageId != -1) ||
127,745,503!
945
      (pCtx->saveHandle.pState && pTuplePos->streamTupleKey.ts > 0)) {
×
946
    int32_t numOfCols = pCtx->subsidiaries.num;
127,752,418✔
947
    char*   p = NULL;
127,752,418✔
948
    int32_t code = loadTupleData(pCtx, pTuplePos, &p);
127,752,418✔
949
    if (p == NULL || TSDB_CODE_SUCCESS != code) {
128,628,955!
950
      qError("Load tuple data failed since %s, groupId:%" PRIu64 ", ts:%" PRId64, terrstr(),
×
951
             pTuplePos->streamTupleKey.groupId, pTuplePos->streamTupleKey.ts);
952
      return TSDB_CODE_NOT_FOUND;
×
953
    }
954

955
    bool* nullList = (bool*)p;
128,630,832✔
956
    char* pStart = (char*)(nullList + numOfCols * sizeof(bool));
128,630,832✔
957

958
    // todo set the offset value to optimize the performance.
959
    for (int32_t j = 0; j < numOfCols; ++j) {
256,859,540✔
960
      SqlFunctionCtx* pc = pCtx->subsidiaries.pCtx[j];
128,665,106✔
961
      int32_t         dstSlotId = pc->pExpr->base.resSchema.slotId;
128,665,106✔
962

963
      // group_key function has its own process function
964
      // do not process there
965
      if (fmIsGroupKeyFunc(pc->functionId)) {
128,665,106✔
966
        continue;
35,682✔
967
      }
968

969
      SColumnInfoData* pDstCol = taosArrayGet(pBlock->pDataBlock, dstSlotId);
128,633,556✔
970
      if (NULL == pDstCol) {
128,508,774!
971
        return TSDB_CODE_OUT_OF_RANGE;
×
972
      }
973
      if (nullList[j]) {
128,508,774✔
974
        colDataSetNULL(pDstCol, rowIndex);
214!
975
      } else {
976
        code = colDataSetVal(pDstCol, rowIndex, pStart, false);
128,508,560✔
977
        if (TSDB_CODE_SUCCESS != code) {
128,192,812!
978
          return code;
×
979
        }
980
      }
981
      pStart += pDstCol->info.bytes;
128,193,026✔
982
    }
983
  }
984

985
  return TSDB_CODE_SUCCESS;
128,187,519✔
986
}
987

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

995
  int32_t code = TSDB_CODE_SUCCESS;
55,482,600✔
996
  for (int32_t j = 0; j < pCtx->subsidiaries.num; ++j) {
110,959,708✔
997
    SqlFunctionCtx* pc = pCtx->subsidiaries.pCtx[j];
55,485,254✔
998

999
    // get data from source col
1000
    SFunctParam* pFuncParam = &pc->pExpr->base.pParam[0];
55,485,254✔
1001
    int32_t      srcSlotId = pFuncParam->pCol->slotId;
55,485,254✔
1002

1003
    SColumnInfoData* pSrcCol = taosArrayGet(pCtx->pSrcBlock->pDataBlock, srcSlotId);
55,485,254✔
1004
    if (NULL == pSrcCol) {
55,478,764!
1005
      return TSDB_CODE_OUT_OF_RANGE;
×
1006
    }
1007

1008
    char* pData = colDataGetData(pSrcCol, rowIndex);
55,478,764!
1009

1010
    // append to dest col
1011
    int32_t dstSlotId = pc->pExpr->base.resSchema.slotId;
55,478,764✔
1012

1013
    SColumnInfoData* pDstCol = taosArrayGet(pCtx->pDstBlock->pDataBlock, dstSlotId);
55,478,764✔
1014
    if (NULL == pDstCol) {
55,463,650!
1015
      return TSDB_CODE_OUT_OF_RANGE;
×
1016
    }
1017

1018
    if (colDataIsNull_s(pSrcCol, rowIndex) == true) {
110,927,300✔
1019
      colDataSetNULL(pDstCol, pos);
392✔
1020
    } else {
1021
      code = colDataSetVal(pDstCol, pos, pData, false);
55,463,258✔
1022
      if (TSDB_CODE_SUCCESS != code) {
55,476,716!
1023
        return code;
×
1024
      }
1025
    }
1026
  }
1027
  return code;
55,474,454✔
1028
}
1029

1030
void replaceTupleData(STuplePos* pDestPos, STuplePos* pSourcePos) { *pDestPos = *pSourcePos; }
32✔
1031

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

1037
  SResultRowEntryInfo* pSResInfo = GET_RES_INFO(pSourceCtx);
57✔
1038
  SMinmaxResInfo*      pSBuf = GET_ROWCELL_INTERBUF(pSResInfo);
57✔
1039
  int16_t              type = pDBuf->type == TSDB_DATA_TYPE_NULL ? pSBuf->type : pDBuf->type;
57✔
1040

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

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

1104
int32_t getStdInfoSize() { return (int32_t)sizeof(SStdRes); }
1,169,896✔
1105

1106
bool getStdFuncEnv(SFunctionNode* pFunc, SFuncExecEnv* pEnv) {
157,469✔
1107
  pEnv->calcMemSize = sizeof(SStdRes);
157,469✔
1108
  return true;
157,469✔
1109
}
1110

1111
int32_t stdFunctionSetup(SqlFunctionCtx* pCtx, SResultRowEntryInfo* pResultInfo) {
8,100,089✔
1112
  if (pResultInfo->initialized) {
8,100,089!
1113
    return TSDB_CODE_SUCCESS;
×
1114
  }
1115
  if (TSDB_CODE_SUCCESS != functionSetup(pCtx, pResultInfo)) {
8,100,089!
1116
    return TSDB_CODE_FUNC_SETUP_ERROR;
×
1117
  }
1118

1119
  SStdRes* pRes = GET_ROWCELL_INTERBUF(pResultInfo);
8,100,103✔
1120
  (void)memset(pRes, 0, sizeof(SStdRes));
8,100,103✔
1121
  return TSDB_CODE_SUCCESS;
8,100,103✔
1122
}
1123

1124
int32_t stdFunction(SqlFunctionCtx* pCtx) {
8,051,615✔
1125
  int32_t numOfElem = 0;
8,051,615✔
1126

1127
  // Only the pre-computing information loaded and actual data does not loaded
1128
  SInputColumnInfoData* pInput = &pCtx->input;
8,051,615✔
1129
  int32_t               type = pInput->pData[0]->info.type;
8,051,615✔
1130

1131
  SStdRes* pStdRes = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
8,051,615✔
1132
  pStdRes->type = type;
8,051,615✔
1133

1134
  // computing based on the true data block
1135
  SColumnInfoData* pCol = pInput->pData[0];
8,051,615✔
1136

1137
  int32_t start = pInput->startRowIndex;
8,051,615✔
1138
  int32_t numOfRows = pInput->numOfRows;
8,051,615✔
1139

1140
  if (IS_NULL_TYPE(type)) {
8,051,615✔
1141
    numOfElem = 0;
114✔
1142
    goto _stddev_over;
114✔
1143
  }
1144

1145
  switch (type) {
8,051,501!
1146
    case TSDB_DATA_TYPE_TINYINT: {
17,361✔
1147
      int8_t* plist = (int8_t*)pCol->pData;
17,361✔
1148
      for (int32_t i = start; i < numOfRows + start; ++i) {
211,922✔
1149
        if (pCol->hasNull && colDataIsNull_f(pCol->nullbitmap, i)) {
194,561✔
1150
          continue;
28,463✔
1151
        }
1152

1153
        numOfElem += 1;
166,098✔
1154
        pStdRes->count += 1;
166,098✔
1155
        pStdRes->isum += plist[i];
166,098✔
1156
        pStdRes->quadraticISum += plist[i] * plist[i];
166,098✔
1157
      }
1158

1159
      break;
17,361✔
1160
    }
1161

1162
    case TSDB_DATA_TYPE_SMALLINT: {
238,418✔
1163
      int16_t* plist = (int16_t*)pCol->pData;
238,418✔
1164
      for (int32_t i = start; i < numOfRows + pInput->startRowIndex; ++i) {
1,435,584✔
1165
        if (pCol->hasNull && colDataIsNull_f(pCol->nullbitmap, i)) {
1,197,166✔
1166
          continue;
211,034✔
1167
        }
1168

1169
        numOfElem += 1;
986,132✔
1170
        pStdRes->count += 1;
986,132✔
1171
        pStdRes->isum += plist[i];
986,132✔
1172
        pStdRes->quadraticISum += plist[i] * plist[i];
986,132✔
1173
      }
1174
      break;
238,418✔
1175
    }
1176

1177
    case TSDB_DATA_TYPE_INT: {
21,271✔
1178
      int32_t* plist = (int32_t*)pCol->pData;
21,271✔
1179
      for (int32_t i = start; i < numOfRows + pInput->startRowIndex; ++i) {
659,215✔
1180
        if (pCol->hasNull && colDataIsNull_f(pCol->nullbitmap, i)) {
637,944✔
1181
          continue;
170,422✔
1182
        }
1183

1184
        numOfElem += 1;
467,522✔
1185
        pStdRes->count += 1;
467,522✔
1186
        pStdRes->isum += plist[i];
467,522✔
1187
        pStdRes->quadraticISum += plist[i] * plist[i];
467,522✔
1188
      }
1189

1190
      break;
21,271✔
1191
    }
1192

1193
    case TSDB_DATA_TYPE_BIGINT: {
2,225,610✔
1194
      int64_t* plist = (int64_t*)pCol->pData;
2,225,610✔
1195
      for (int32_t i = start; i < numOfRows + pInput->startRowIndex; ++i) {
7,612,262✔
1196
        if (pCol->hasNull && colDataIsNull_f(pCol->nullbitmap, i)) {
5,386,652✔
1197
          continue;
25,363✔
1198
        }
1199

1200
        numOfElem += 1;
5,361,289✔
1201
        pStdRes->count += 1;
5,361,289✔
1202
        pStdRes->isum += plist[i];
5,361,289✔
1203
        pStdRes->quadraticISum += plist[i] * plist[i];
5,361,289✔
1204
      }
1205
      break;
2,225,610✔
1206
    }
1207

1208
    case TSDB_DATA_TYPE_UTINYINT: {
1✔
1209
      uint8_t* plist = (uint8_t*)pCol->pData;
1✔
1210
      for (int32_t i = start; i < numOfRows + start; ++i) {
8✔
1211
        if (pCol->hasNull && colDataIsNull_f(pCol->nullbitmap, i)) {
7!
1212
          continue;
4✔
1213
        }
1214

1215
        numOfElem += 1;
3✔
1216
        pStdRes->count += 1;
3✔
1217
        pStdRes->usum += plist[i];
3✔
1218
        pStdRes->quadraticUSum += plist[i] * plist[i];
3✔
1219
      }
1220

1221
      break;
1✔
1222
    }
1223

1224
    case TSDB_DATA_TYPE_USMALLINT: {
×
1225
      uint16_t* plist = (uint16_t*)pCol->pData;
×
1226
      for (int32_t i = start; i < numOfRows + pInput->startRowIndex; ++i) {
×
1227
        if (pCol->hasNull && colDataIsNull_f(pCol->nullbitmap, i)) {
×
1228
          continue;
×
1229
        }
1230

1231
        numOfElem += 1;
×
1232
        pStdRes->count += 1;
×
1233
        pStdRes->usum += plist[i];
×
1234
        pStdRes->quadraticUSum += plist[i] * plist[i];
×
1235
      }
1236
      break;
×
1237
    }
1238

1239
    case TSDB_DATA_TYPE_UINT: {
1✔
1240
      uint32_t* plist = (uint32_t*)pCol->pData;
1✔
1241
      for (int32_t i = start; i < numOfRows + pInput->startRowIndex; ++i) {
6✔
1242
        if (pCol->hasNull && colDataIsNull_f(pCol->nullbitmap, i)) {
5!
1243
          continue;
×
1244
        }
1245

1246
        numOfElem += 1;
5✔
1247
        pStdRes->count += 1;
5✔
1248
        pStdRes->usum += plist[i];
5✔
1249
        pStdRes->quadraticUSum += plist[i] * plist[i];
5✔
1250
      }
1251

1252
      break;
1✔
1253
    }
1254

1255
    case TSDB_DATA_TYPE_UBIGINT: {
×
1256
      uint64_t* plist = (uint64_t*)pCol->pData;
×
1257
      for (int32_t i = start; i < numOfRows + pInput->startRowIndex; ++i) {
×
1258
        if (pCol->hasNull && colDataIsNull_f(pCol->nullbitmap, i)) {
×
1259
          continue;
×
1260
        }
1261

1262
        numOfElem += 1;
×
1263
        pStdRes->count += 1;
×
1264
        pStdRes->usum += plist[i];
×
1265
        pStdRes->quadraticUSum += plist[i] * plist[i];
×
1266
      }
1267
      break;
×
1268
    }
1269

1270
    case TSDB_DATA_TYPE_FLOAT: {
17,373✔
1271
      float* plist = (float*)pCol->pData;
17,373✔
1272
      for (int32_t i = start; i < numOfRows + pInput->startRowIndex; ++i) {
1,877,405✔
1273
        if (pCol->hasNull && colDataIsNull_f(pCol->nullbitmap, i)) {
1,860,032✔
1274
          continue;
33,208✔
1275
        }
1276

1277
        numOfElem += 1;
1,826,824✔
1278
        pStdRes->count += 1;
1,826,824✔
1279
        pStdRes->dsum += plist[i];
1,826,824✔
1280
        pStdRes->quadraticDSum += plist[i] * plist[i];
1,826,824✔
1281
      }
1282
      break;
17,373✔
1283
    }
1284

1285
    case TSDB_DATA_TYPE_DOUBLE: {
5,531,814✔
1286
      double* plist = (double*)pCol->pData;
5,531,814✔
1287
      for (int32_t i = start; i < numOfRows + pInput->startRowIndex; ++i) {
22,577,801✔
1288
        if (pCol->hasNull && colDataIsNull_f(pCol->nullbitmap, i)) {
17,045,987✔
1289
          continue;
586,432✔
1290
        }
1291

1292
        numOfElem += 1;
16,459,555✔
1293
        pStdRes->count += 1;
16,459,555✔
1294
        pStdRes->dsum += plist[i];
16,459,555✔
1295
        pStdRes->quadraticDSum += plist[i] * plist[i];
16,459,555✔
1296
      }
1297
      break;
5,531,814✔
1298
    }
1299

1300
    default:
×
1301
      break;
×
1302
  }
1303

1304
_stddev_over:
8,051,615✔
1305
  // data in the check operation are all null, not output
1306
  SET_VAL(GET_RES_INFO(pCtx), numOfElem, 1);
8,051,615✔
1307
  return TSDB_CODE_SUCCESS;
8,051,615✔
1308
}
1309

1310
static void stdTransferInfo(SStdRes* pInput, SStdRes* pOutput) {
1,168,126✔
1311
  if (IS_NULL_TYPE(pInput->type)) {
1,168,126✔
1312
    return;
80✔
1313
  }
1314
  pOutput->type = pInput->type;
1,168,046✔
1315
  if (IS_SIGNED_NUMERIC_TYPE(pOutput->type)) {
1,168,046!
1316
    pOutput->quadraticISum += pInput->quadraticISum;
8,036✔
1317
    pOutput->isum += pInput->isum;
8,036✔
1318
  } else if (IS_UNSIGNED_NUMERIC_TYPE(pOutput->type)) {
1,160,010!
1319
    pOutput->quadraticUSum += pInput->quadraticUSum;
1✔
1320
    pOutput->usum += pInput->usum;
1✔
1321
  } else {
1322
    pOutput->quadraticDSum += pInput->quadraticDSum;
1,160,009✔
1323
    pOutput->dsum += pInput->dsum;
1,160,009✔
1324
  }
1325

1326
  pOutput->count += pInput->count;
1,168,046✔
1327
}
1328

1329
int32_t stdFunctionMerge(SqlFunctionCtx* pCtx) {
1,168,073✔
1330
  SInputColumnInfoData* pInput = &pCtx->input;
1,168,073✔
1331
  SColumnInfoData*      pCol = pInput->pData[0];
1,168,073✔
1332

1333
  if (IS_NULL_TYPE(pCol->info.type)) {
1,168,073!
1334
    SET_VAL(GET_RES_INFO(pCtx), 0, 1);
×
1335
    return TSDB_CODE_SUCCESS;
×
1336
  }
1337

1338
  if (pCol->info.type != TSDB_DATA_TYPE_BINARY) {
1,168,073!
1339
    return TSDB_CODE_FUNC_FUNTION_PARA_TYPE;
×
1340
  }
1341

1342
  SStdRes* pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
1,168,073✔
1343

1344
  for (int32_t i = pInput->startRowIndex; i < pInput->startRowIndex + pInput->numOfRows; ++i) {
2,336,196✔
1345
    if (colDataIsNull_s(pCol, i)) continue;
2,336,246!
1346
    char*    data = colDataGetData(pCol, i);
1,168,123!
1347
    SStdRes* pInputInfo = (SStdRes*)varDataVal(data);
1,168,123✔
1348
    stdTransferInfo(pInputInfo, pInfo);
1,168,123✔
1349
  }
1350

1351
  SET_VAL(GET_RES_INFO(pCtx), 1, 1);
1,168,073✔
1352
  return TSDB_CODE_SUCCESS;
1,168,073✔
1353
}
1354

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

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

1363
  SStdRes* pStdRes = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
1364

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

1368
  int32_t start = pInput->startRowIndex;
1369
  int32_t numOfRows = pInput->numOfRows;
1370

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

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

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

1428
  if (pStddevRes->count == 0) {
6,894,624✔
1429
    GET_RES_INFO(pCtx)->numOfRes = 0;
51,770✔
1430
    return functionFinalize(pCtx, pBlock);
51,770✔
1431
  }
1432

1433
  if (IS_SIGNED_NUMERIC_TYPE(type)) {
6,842,854!
1434
    avg = pStddevRes->isum / ((double)pStddevRes->count);
2,421,807✔
1435
    pStddevRes->result = sqrt(fabs(pStddevRes->quadraticISum / ((double)pStddevRes->count) - avg * avg));
2,421,807✔
1436
  } else if (IS_UNSIGNED_NUMERIC_TYPE(type)) {
4,421,047!
1437
    avg = pStddevRes->usum / ((double)pStddevRes->count);
2✔
1438
    pStddevRes->result = sqrt(fabs(pStddevRes->quadraticUSum / ((double)pStddevRes->count) - avg * avg));
2✔
1439
  } else {
1440
    avg = pStddevRes->dsum / ((double)pStddevRes->count);
4,421,045✔
1441
    pStddevRes->result = sqrt(fabs(pStddevRes->quadraticDSum / ((double)pStddevRes->count) - avg * avg));
4,421,045✔
1442
  }
1443

1444
  // check for overflow
1445
  if (isinf(pStddevRes->result) || isnan(pStddevRes->result)) {
6,842,854!
1446
    GET_RES_INFO(pCtx)->numOfRes = 0;
×
1447
  }
1448

1449
  return functionFinalize(pCtx, pBlock);
6,842,854✔
1450
}
1451

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

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

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

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

1479
  return functionFinalize(pCtx, pBlock);
×
1480
}
1481

1482
int32_t stdPartialFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
1,168,310✔
1483
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
1,168,310✔
1484
  SStdRes*             pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
1,168,310✔
1485
  int32_t              resultBytes = getStdInfoSize();
1,168,310✔
1486
  char*                res = taosMemoryCalloc(resultBytes + VARSTR_HEADER_SIZE, sizeof(char));
1,168,310!
1487

1488
  if (NULL == res) {
1,168,310!
1489
    return terrno;
×
1490
  }
1491
  (void)memcpy(varDataVal(res), pInfo, resultBytes);
1,168,310✔
1492
  varDataSetLen(res, resultBytes);
1,168,310✔
1493

1494
  int32_t          slotId = pCtx->pExpr->base.resSchema.slotId;
1,168,310✔
1495
  SColumnInfoData* pCol = taosArrayGet(pBlock->pDataBlock, slotId);
1,168,310✔
1496
  if (NULL == pCol) {
1,168,310!
1497
    taosMemoryFree(res);
×
1498
    return TSDB_CODE_OUT_OF_RANGE;
×
1499
  }
1500

1501
  int32_t code = colDataSetVal(pCol, pBlock->info.rows, res, false);
1,168,310✔
1502

1503
  taosMemoryFree(res);
1,168,310!
1504
  return code;
1,168,310✔
1505
}
1506

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

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

1515
  stdTransferInfo(pSBuf, pDBuf);
3✔
1516

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

1522
bool getLeastSQRFuncEnv(SFunctionNode* pFunc, SFuncExecEnv* pEnv) {
42,760✔
1523
  pEnv->calcMemSize = sizeof(SLeastSQRInfo);
42,760✔
1524
  return true;
42,760✔
1525
}
1526

1527
int32_t leastSQRFunctionSetup(SqlFunctionCtx* pCtx, SResultRowEntryInfo* pResultInfo) {
5,628,625✔
1528
  if (pResultInfo->initialized) {
5,628,625!
1529
    return TSDB_CODE_SUCCESS;
×
1530
  }
1531
  if (TSDB_CODE_SUCCESS != functionSetup(pCtx, pResultInfo)) {
5,628,625!
1532
    return TSDB_CODE_FUNC_SETUP_ERROR;
×
1533
  }
1534

1535
  SLeastSQRInfo* pInfo = GET_ROWCELL_INTERBUF(pResultInfo);
5,628,635✔
1536

1537
  GET_TYPED_DATA(pInfo->startVal, double, pCtx->param[1].param.nType, &pCtx->param[1].param.i);
5,628,635!
1538
  GET_TYPED_DATA(pInfo->stepVal, double, pCtx->param[2].param.nType, &pCtx->param[2].param.i);
5,628,635!
1539
  return TSDB_CODE_SUCCESS;
5,628,635✔
1540
}
1541

1542
int32_t leastSQRFunction(SqlFunctionCtx* pCtx) {
6,838,320✔
1543
  int32_t numOfElem = 0;
6,838,320✔
1544

1545
  SInputColumnInfoData* pInput = &pCtx->input;
6,838,320✔
1546
  int32_t               type = pInput->pData[0]->info.type;
6,838,320✔
1547

1548
  SLeastSQRInfo* pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
6,838,320✔
1549

1550
  SColumnInfoData* pCol = pInput->pData[0];
6,838,320✔
1551

1552
  double(*param)[3] = pInfo->matrix;
6,838,320✔
1553
  double x = pInfo->startVal;
6,838,320✔
1554

1555
  int32_t start = pInput->startRowIndex;
6,838,320✔
1556
  int32_t numOfRows = pInput->numOfRows;
6,838,320✔
1557

1558
  switch (type) {
6,838,320!
1559
    case TSDB_DATA_TYPE_TINYINT: {
11,256✔
1560
      int8_t* plist = (int8_t*)pCol->pData;
11,256✔
1561
      for (int32_t i = start; i < numOfRows + pInput->startRowIndex; ++i) {
491,482✔
1562
        if (pCol->hasNull && colDataIsNull_f(pCol->nullbitmap, i)) {
480,226✔
1563
          continue;
3,036✔
1564
        }
1565
        numOfElem++;
477,190✔
1566
        LEASTSQR_CAL(param, x, plist, i, pInfo->stepVal);
477,190✔
1567
      }
1568
      break;
11,256✔
1569
    }
1570
    case TSDB_DATA_TYPE_SMALLINT: {
10,815✔
1571
      int16_t* plist = (int16_t*)pCol->pData;
10,815✔
1572
      for (int32_t i = start; i < numOfRows + pInput->startRowIndex; ++i) {
300,920✔
1573
        if (pCol->hasNull && colDataIsNull_f(pCol->nullbitmap, i)) {
290,105✔
1574
          continue;
287,089✔
1575
        }
1576

1577
        numOfElem++;
3,016✔
1578
        LEASTSQR_CAL(param, x, plist, i, pInfo->stepVal);
3,016✔
1579
      }
1580
      break;
10,815✔
1581
    }
1582

1583
    case TSDB_DATA_TYPE_INT: {
4,965,537✔
1584
      int32_t* plist = (int32_t*)pCol->pData;
4,965,537✔
1585
      for (int32_t i = start; i < numOfRows + pInput->startRowIndex; ++i) {
18,288,473✔
1586
        if (pCol->hasNull && colDataIsNull_f(pCol->nullbitmap, i)) {
13,322,936✔
1587
          continue;
275,148✔
1588
        }
1589

1590
        numOfElem++;
13,047,788✔
1591
        LEASTSQR_CAL(param, x, plist, i, pInfo->stepVal);
13,047,788✔
1592
      }
1593
      break;
4,965,537✔
1594
    }
1595

1596
    case TSDB_DATA_TYPE_BIGINT: {
8,090✔
1597
      int64_t* plist = (int64_t*)pCol->pData;
8,090✔
1598
      for (int32_t i = start; i < numOfRows + pInput->startRowIndex; ++i) {
159,329✔
1599
        if (pCol->hasNull && colDataIsNull_f(pCol->nullbitmap, i)) {
151,239✔
1600
          continue;
1,636✔
1601
        }
1602

1603
        numOfElem++;
149,603✔
1604
        LEASTSQR_CAL(param, x, plist, i, pInfo->stepVal);
149,603✔
1605
      }
1606
      break;
8,090✔
1607
    }
1608

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

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

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

1640
        numOfElem++;
192✔
1641
        LEASTSQR_CAL(param, x, plist, i, pInfo->stepVal);
192✔
1642
      }
1643
      break;
72✔
1644
    }
1645

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

1653
        numOfElem++;
192✔
1654
        LEASTSQR_CAL(param, x, plist, i, pInfo->stepVal);
192✔
1655
      }
1656
      break;
72✔
1657
    }
1658

1659
    case TSDB_DATA_TYPE_FLOAT: {
1,833,645✔
1660
      float* plist = (float*)pCol->pData;
1,833,645✔
1661
      for (int32_t i = start; i < numOfRows + pInput->startRowIndex; ++i) {
5,707,957✔
1662
        if (pCol->hasNull && colDataIsNull_f(pCol->nullbitmap, i)) {
3,874,312✔
1663
          continue;
1,836✔
1664
        }
1665

1666
        numOfElem++;
3,872,476✔
1667
        LEASTSQR_CAL(param, x, plist, i, pInfo->stepVal);
3,872,476✔
1668
      }
1669
      break;
1,833,645✔
1670
    }
1671

1672
    case TSDB_DATA_TYPE_DOUBLE: {
8,692✔
1673
      double* plist = (double*)pCol->pData;
8,692✔
1674
      for (int32_t i = start; i < numOfRows + pInput->startRowIndex; ++i) {
594,832✔
1675
        if (pCol->hasNull && colDataIsNull_f(pCol->nullbitmap, i)) {
586,140✔
1676
          continue;
2,436✔
1677
        }
1678

1679
        numOfElem++;
583,704✔
1680
        LEASTSQR_CAL(param, x, plist, i, pInfo->stepVal);
583,704✔
1681
      }
1682
      break;
8,692✔
1683
    }
1684
    case TSDB_DATA_TYPE_NULL: {
×
1685
      GET_RES_INFO(pCtx)->isNullRes = 1;
×
1686
      numOfElem = 1;
×
1687
      break;
×
1688
    }
1689

1690
    default:
×
1691
      break;
×
1692
  }
1693

1694
  pInfo->startVal = x;
6,838,320✔
1695
  pInfo->num += numOfElem;
6,838,320✔
1696

1697
  SET_VAL(GET_RES_INFO(pCtx), numOfElem, 1);
6,838,320✔
1698

1699
  return TSDB_CODE_SUCCESS;
6,838,320✔
1700
}
1701

1702
int32_t leastSQRFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
5,625,346✔
1703
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
5,625,346✔
1704
  SLeastSQRInfo*       pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
5,625,346✔
1705
  int32_t              slotId = pCtx->pExpr->base.resSchema.slotId;
5,625,346✔
1706
  SColumnInfoData*     pCol = taosArrayGet(pBlock->pDataBlock, slotId);
5,625,346✔
1707

1708
  if (NULL == pCol) {
5,625,347!
1709
    return TSDB_CODE_OUT_OF_RANGE;
×
1710
  }
1711
  int32_t currentRow = pBlock->info.rows;
5,625,347✔
1712

1713
  if (0 == pInfo->num) {
5,625,347✔
1714
    colDataSetNULL(pCol, currentRow);
19,069!
1715
    return TSDB_CODE_SUCCESS;
19,069✔
1716
  }
1717

1718
  double(*param)[3] = pInfo->matrix;
5,606,278✔
1719

1720
  param[1][1] = (double)pInfo->num;
5,606,278✔
1721
  param[1][0] = param[0][1];
5,606,278✔
1722

1723
  double param00 = param[0][0] - param[1][0] * (param[0][1] / param[1][1]);
5,606,278✔
1724
  double param02 = param[0][2] - param[1][2] * (param[0][1] / param[1][1]);
5,606,278✔
1725

1726
  if (0 == param00) {
5,606,278✔
1727
    colDataSetNULL(pCol, currentRow);
3,811,205!
1728
    return TSDB_CODE_SUCCESS;
3,811,205✔
1729
  }
1730

1731
  // param[0][1] = 0;
1732
  double param12 = param[1][2] - param02 * (param[1][0] / param00);
1,795,073✔
1733
  // param[1][0] = 0;
1734
  param02 /= param00;
1,795,073✔
1735

1736
  param12 /= param[1][1];
1,795,073✔
1737

1738
  char buf[LEASTSQUARES_BUFF_LENGTH] = {0};
1,795,073✔
1739
  char slopBuf[64] = {0};
1,795,073✔
1740
  char interceptBuf[64] = {0};
1,795,073✔
1741
  int  n = tsnprintf(slopBuf, 64, "%.6lf", param02);
1,795,073✔
1742
  if (n > LEASTSQUARES_DOUBLE_ITEM_LENGTH) {
1,795,075✔
1743
    (void)snprintf(slopBuf, 64, "%." DOUBLE_PRECISION_DIGITS, param02);
6✔
1744
  }
1745
  n = tsnprintf(interceptBuf, 64, "%.6lf", param12);
1,795,075✔
1746
  if (n > LEASTSQUARES_DOUBLE_ITEM_LENGTH) {
1,795,078✔
1747
    (void)snprintf(interceptBuf, 64, "%." DOUBLE_PRECISION_DIGITS, param12);
972✔
1748
  }
1749
  size_t len =
1,795,078✔
1750
      snprintf(varDataVal(buf), sizeof(buf) - VARSTR_HEADER_SIZE, "{slop:%s, intercept:%s}", slopBuf, interceptBuf);
1,795,078✔
1751
  varDataSetLen(buf, len);
1,795,078✔
1752

1753
  int32_t code = colDataSetVal(pCol, currentRow, buf, pResInfo->isNullRes);
1,795,078✔
1754

1755
  return code;
1,795,076✔
1756
}
1757

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

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

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

1785
int32_t percentileFunctionSetup(SqlFunctionCtx* pCtx, SResultRowEntryInfo* pResultInfo) {
6,253✔
1786
  if (pResultInfo->initialized) {
6,253!
1787
    return TSDB_CODE_SUCCESS;
×
1788
  }
1789
  if (TSDB_CODE_SUCCESS != functionSetup(pCtx, pResultInfo)) {
6,253!
1790
    return TSDB_CODE_FUNC_SETUP_ERROR;
×
1791
  }
1792

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

1799
  return TSDB_CODE_SUCCESS;
6,253✔
1800
}
1801

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

1813
int32_t percentileFunction(SqlFunctionCtx* pCtx) {
2,092,372✔
1814
  int32_t              code = TSDB_CODE_SUCCESS;
2,092,372✔
1815
  int32_t              numOfElems = 0;
2,092,372✔
1816
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
2,092,372✔
1817

1818
  SInputColumnInfoData* pInput = &pCtx->input;
2,092,372✔
1819
  SColumnDataAgg*       pAgg = pInput->pColumnDataAgg[0];
2,092,372✔
1820

1821
  SColumnInfoData* pCol = pInput->pData[0];
2,092,372✔
1822
  int32_t          type = pCol->info.type;
2,092,372✔
1823

1824
  SPercentileInfo* pInfo = GET_ROWCELL_INTERBUF(pResInfo);
2,092,372✔
1825
  if (pCtx->scanFlag == MAIN_SCAN && pInfo->stage == 0) {
2,092,372✔
1826
    pInfo->stage += 1;
6,253✔
1827

1828
    // all data are null, set it completed
1829
    if (pInfo->numOfElems == 0) {
6,253✔
1830
      pResInfo->complete = true;
2,176✔
1831
      return TSDB_CODE_SUCCESS;
2,176✔
1832
    } else {
1833
      code = tMemBucketCreate(pCol->info.bytes, type, pInfo->minval, pInfo->maxval, pCtx->hasWindowOrGroup,
4,077✔
1834
                              &pInfo->pMemBucket, pInfo->numOfElems);
4,077✔
1835
      if (TSDB_CODE_SUCCESS != code) {
4,077!
1836
        return code;
×
1837
      }
1838
    }
1839
  }
1840

1841
  // the first stage, only acquire the min/max value
1842
  if (pInfo->stage == 0) {
2,090,196✔
1843
    if (pCtx->input.colDataSMAIsSet) {
1,046,200✔
1844
      double tmin = 0.0, tmax = 0.0;
1,036,567✔
1845
      if (IS_SIGNED_NUMERIC_TYPE(type)) {
1,036,567!
1846
        tmin = (double)GET_INT64_VAL(&pAgg->min);
×
1847
        tmax = (double)GET_INT64_VAL(&pAgg->max);
×
1848
      } else if (IS_FLOAT_TYPE(type)) {
1,036,567!
1849
        tmin = GET_DOUBLE_VAL(&pAgg->min);
1,036,567✔
1850
        tmax = GET_DOUBLE_VAL(&pAgg->max);
1,036,567✔
1851
      } else if (IS_UNSIGNED_NUMERIC_TYPE(type)) {
×
1852
        tmin = (double)GET_UINT64_VAL(&pAgg->min);
×
1853
        tmax = (double)GET_UINT64_VAL(&pAgg->max);
×
1854
      }
1855

1856
      if (GET_DOUBLE_VAL(&pInfo->minval) > tmin) {
1,036,567✔
1857
        SET_DOUBLE_VAL(&pInfo->minval, tmin);
14✔
1858
      }
1859

1860
      if (GET_DOUBLE_VAL(&pInfo->maxval) < tmax) {
1,036,567✔
1861
        SET_DOUBLE_VAL(&pInfo->maxval, tmax);
28✔
1862
      }
1863

1864
      pInfo->numOfElems += (pInput->numOfRows - pAgg->numOfNull);
1,036,567✔
1865
    } else {
1866
      // check the valid data one by one
1867
      int32_t start = pInput->startRowIndex;
9,633✔
1868
      for (int32_t i = start; i < pInput->numOfRows + start; ++i) {
10,182,336✔
1869
        if (colDataIsNull_f(pCol->nullbitmap, i)) {
10,172,703✔
1870
          continue;
2,600✔
1871
        }
1872

1873
        char* data = colDataGetData(pCol, i);
10,170,103!
1874

1875
        double v = 0;
10,170,103✔
1876
        GET_TYPED_DATA(v, double, type, data);
10,170,103!
1877
        if (v < GET_DOUBLE_VAL(&pInfo->minval)) {
10,170,103✔
1878
          SET_DOUBLE_VAL(&pInfo->minval, v);
4,305✔
1879
        }
1880

1881
        if (v > GET_DOUBLE_VAL(&pInfo->maxval)) {
10,170,103✔
1882
          SET_DOUBLE_VAL(&pInfo->maxval, v);
409,605✔
1883
        }
1884

1885
        pInfo->numOfElems += 1;
10,170,103✔
1886
      }
1887
    }
1888
  } else {
1889
    // the second stage, calculate the true percentile value
1890
    int32_t start = pInput->startRowIndex;
1,043,996✔
1891
    for (int32_t i = start; i < pInput->numOfRows + start; ++i) {
2,147,483,647✔
1892
      if (colDataIsNull_f(pCol->nullbitmap, i)) {
2,147,483,647!
1893
        continue;
×
1894
      }
1895

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

1905
    SET_VAL(pResInfo, numOfElems, 1);
1,043,996!
1906
  }
1907

1908
  pCtx->needCleanup = true;
2,090,196✔
1909
  return TSDB_CODE_SUCCESS;
2,090,196✔
1910
}
1911

1912
int32_t percentileFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
6,253✔
1913
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
6,253✔
1914
  SPercentileInfo*     ppInfo = (SPercentileInfo*)GET_ROWCELL_INTERBUF(pResInfo);
6,253✔
1915

1916
  int32_t code = 0;
6,253✔
1917
  double  v = 0;
6,253✔
1918

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

1927
      varDataVal(buf)[0] = '[';
22✔
1928
      for (int32_t i = 1; i < pCtx->numOfParams; ++i) {
210✔
1929
        SVariant* pVal = &pCtx->param[i].param;
188✔
1930

1931
        GET_TYPED_DATA(v, double, pVal->nType, &pVal->i);
188!
1932

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

1938
        if (i == pCtx->numOfParams - 1) {
188✔
1939
          len += tsnprintf(varDataVal(buf) + len, sizeof(buf) - VARSTR_HEADER_SIZE - len, "%.6lf]", ppInfo->result);
22✔
1940
        } else {
1941
          len += tsnprintf(varDataVal(buf) + len, sizeof(buf) - VARSTR_HEADER_SIZE - len, "%.6lf, ", ppInfo->result);
166✔
1942
        }
1943
      }
1944

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

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

1958
      tMemBucketDestroy(pMemBucket);
22✔
1959
      return TSDB_CODE_SUCCESS;
22✔
1960
    } else {
1961
      SVariant* pVal = &pCtx->param[1].param;
4,055✔
1962

1963
      GET_TYPED_DATA(v, double, pVal->nType, &pVal->i);
4,055!
1964

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

1970
      tMemBucketDestroy(pMemBucket);
4,055✔
1971
      return functionFinalize(pCtx, pBlock);
4,055✔
1972
    }
1973
  } else {
1974
    return functionFinalize(pCtx, pBlock);
2,176✔
1975
  }
1976

1977
_fin_error:
×
1978

1979
  tMemBucketDestroy(pMemBucket);
×
1980
  return code;
×
1981
}
1982

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

1991
int32_t getApercentileMaxSize() {
9,688✔
1992
  int32_t bytesHist =
9,688✔
1993
      (int32_t)(sizeof(SAPercentileInfo) + sizeof(SHistogramInfo) + sizeof(SHistBin) * (MAX_HISTOGRAM_BIN + 1));
1994
  int32_t bytesDigest = (int32_t)(sizeof(SAPercentileInfo) + TDIGEST_SIZE(COMPRESSION));
9,688✔
1995
  return TMAX(bytesHist, bytesDigest);
9,688✔
1996
}
1997

1998
static int8_t getApercentileAlgo(char* algoStr) {
23,061✔
1999
  int8_t algoType;
2000
  if (strcasecmp(algoStr, "default") == 0) {
23,061✔
2001
    algoType = APERCT_ALGO_DEFAULT;
11,144✔
2002
  } else if (strcasecmp(algoStr, "t-digest") == 0) {
11,917✔
2003
    algoType = APERCT_ALGO_TDIGEST;
11,912✔
2004
  } else {
2005
    algoType = APERCT_ALGO_UNKNOWN;
5✔
2006
  }
2007

2008
  return algoType;
23,061✔
2009
}
2010

2011
static void buildHistogramInfo(SAPercentileInfo* pInfo) {
953,662✔
2012
  pInfo->pHisto = (SHistogramInfo*)((char*)pInfo + sizeof(SAPercentileInfo));
953,662✔
2013
  pInfo->pHisto->elems = (SHistBin*)((char*)pInfo->pHisto + sizeof(SHistogramInfo));
953,662✔
2014
}
953,662✔
2015

2016
static void buildTDigestInfo(SAPercentileInfo* pInfo) {
23,904✔
2017
  pInfo->pTDigest = (TDigest*)((char*)pInfo + sizeof(SAPercentileInfo));
23,904✔
2018
}
23,904✔
2019

2020
int32_t apercentileFunctionSetup(SqlFunctionCtx* pCtx, SResultRowEntryInfo* pResultInfo) {
329,857✔
2021
  if (pResultInfo->initialized) {
329,857!
2022
    return TSDB_CODE_SUCCESS;
×
2023
  }
2024
  if (TSDB_CODE_SUCCESS != functionSetup(pCtx, pResultInfo)) {
329,857!
2025
    return TSDB_CODE_FUNC_SETUP_ERROR;
×
2026
  }
2027

2028
  SAPercentileInfo* pInfo = GET_ROWCELL_INTERBUF(pResultInfo);
329,901✔
2029

2030
  SVariant* pVal = &pCtx->param[1].param;
329,901✔
2031
  pInfo->percent = 0;
329,901✔
2032
  GET_TYPED_DATA(pInfo->percent, double, pVal->nType, &pVal->i);
329,901!
2033

2034
  if (pCtx->numOfParams == 2) {
329,901✔
2035
    pInfo->algo = APERCT_ALGO_DEFAULT;
306,844✔
2036
  } else if (pCtx->numOfParams == 3) {
23,057!
2037
    pInfo->algo = getApercentileAlgo(varDataVal(pCtx->param[2].param.pz));
23,063✔
2038
    if (pInfo->algo == APERCT_ALGO_UNKNOWN) {
23,053!
2039
      return TSDB_CODE_FUNC_FUNTION_PARA_VALUE;
×
2040
    }
2041
  }
2042

2043
  char* tmp = (char*)pInfo + sizeof(SAPercentileInfo);
329,891✔
2044
  if (pInfo->algo == APERCT_ALGO_TDIGEST) {
329,891✔
2045
    pInfo->pTDigest = tdigestNewFrom(tmp, COMPRESSION);
11,909✔
2046
  } else {
2047
    buildHistogramInfo(pInfo);
317,982✔
2048
    pInfo->pHisto = tHistogramCreateFrom(tmp, MAX_HISTOGRAM_BIN);
317,989✔
2049
    qDebug("%s set up histogram, numOfElems:%" PRId64 ", numOfEntry:%d, pHisto:%p, elems:%p", __FUNCTION__,
317,995✔
2050
           pInfo->pHisto->numOfElems, pInfo->pHisto->numOfEntries, pInfo->pHisto, pInfo->pHisto->elems);
2051
  }
2052

2053
  return TSDB_CODE_SUCCESS;
329,907✔
2054
}
2055

2056
int32_t apercentileFunction(SqlFunctionCtx* pCtx) {
336,098✔
2057
  int32_t               numOfElems = 0;
336,098✔
2058
  SResultRowEntryInfo*  pResInfo = GET_RES_INFO(pCtx);
336,098✔
2059
  SInputColumnInfoData* pInput = &pCtx->input;
336,098✔
2060

2061
  SColumnInfoData* pCol = pInput->pData[0];
336,098✔
2062
  int32_t          type = pCol->info.type;
336,098✔
2063

2064
  SAPercentileInfo* pInfo = GET_ROWCELL_INTERBUF(pResInfo);
336,098✔
2065

2066
  int32_t start = pInput->startRowIndex;
336,098✔
2067
  if (pInfo->algo == APERCT_ALGO_TDIGEST) {
336,098✔
2068
    buildTDigestInfo(pInfo);
11,854✔
2069
    tdigestAutoFill(pInfo->pTDigest, COMPRESSION);
11,853✔
2070
    for (int32_t i = start; i < pInput->numOfRows + start; ++i) {
789,834✔
2071
      if (colDataIsNull_f(pCol->nullbitmap, i)) {
777,988✔
2072
        continue;
278,295✔
2073
      }
2074
      numOfElems += 1;
499,693✔
2075
      char* data = colDataGetData(pCol, i);
499,693!
2076

2077
      double  v = 0;  // value
499,693✔
2078
      int64_t w = 1;  // weigth
499,693✔
2079
      GET_TYPED_DATA(v, double, type, data);
499,693✔
2080
      int32_t code = tdigestAdd(pInfo->pTDigest, v, w);
499,693✔
2081
      if (code != TSDB_CODE_SUCCESS) {
499,688!
2082
        return code;
×
2083
      }
2084
    }
2085
  } else {
2086
    // might be a race condition here that pHisto can be overwritten or setup function
2087
    // has not been called, need to relink the buffer pHisto points to.
2088
    buildHistogramInfo(pInfo);
324,244✔
2089
    qDebug("%s before add %d elements into histogram, total:%" PRId64 ", numOfEntry:%d, pHisto:%p, elems: %p",
324,241✔
2090
           __FUNCTION__, numOfElems, pInfo->pHisto->numOfElems, pInfo->pHisto->numOfEntries, pInfo->pHisto,
2091
           pInfo->pHisto->elems);
2092
    for (int32_t i = start; i < pInput->numOfRows + start; ++i) {
3,446,363✔
2093
      if (colDataIsNull_f(pCol->nullbitmap, i)) {
3,122,165✔
2094
        continue;
826,341✔
2095
      }
2096
      numOfElems += 1;
2,295,824✔
2097
      char* data = colDataGetData(pCol, i);
2,295,824!
2098

2099
      double v = 0;
2,295,824✔
2100
      GET_TYPED_DATA(v, double, type, data);
2,295,824!
2101
      int32_t code = tHistogramAdd(&pInfo->pHisto, v);
2,295,824✔
2102
      if (code != TSDB_CODE_SUCCESS) {
2,295,779!
2103
        return code;
×
2104
      }
2105
    }
2106

2107
    qDebug("%s after add %d elements into histogram, total:%" PRId64 ", numOfEntry:%d, pHisto:%p, elems: %p",
324,198✔
2108
           __FUNCTION__, numOfElems, pInfo->pHisto->numOfElems, pInfo->pHisto->numOfEntries, pInfo->pHisto,
2109
           pInfo->pHisto->elems);
2110
  }
2111

2112
  SET_VAL(pResInfo, numOfElems, 1);
336,114✔
2113
  return TSDB_CODE_SUCCESS;
336,114✔
2114
}
2115

2116
static int32_t apercentileTransferInfo(SAPercentileInfo* pInput, SAPercentileInfo* pOutput, bool* hasRes) {
8,408✔
2117
  pOutput->percent = pInput->percent;
8,408✔
2118
  pOutput->algo = pInput->algo;
8,408✔
2119
  if (pOutput->algo == APERCT_ALGO_TDIGEST) {
8,408✔
2120
    buildTDigestInfo(pInput);
150✔
2121
    tdigestAutoFill(pInput->pTDigest, COMPRESSION);
150✔
2122

2123
    if (pInput->pTDigest->num_centroids == 0 && pInput->pTDigest->num_buffered_pts == 0) {
150✔
2124
      return TSDB_CODE_SUCCESS;
1✔
2125
    }
2126

2127
    if (hasRes) {
149✔
2128
      *hasRes = true;
147✔
2129
    }
2130

2131
    buildTDigestInfo(pOutput);
149✔
2132
    TDigest* pTDigest = pOutput->pTDigest;
149✔
2133
    tdigestAutoFill(pTDigest, COMPRESSION);
149✔
2134

2135
    if (pTDigest->num_centroids <= 0 && pTDigest->num_buffered_pts == 0) {
149!
2136
      (void)memcpy(pTDigest, pInput->pTDigest, (size_t)TDIGEST_SIZE(COMPRESSION));
147✔
2137
      tdigestAutoFill(pTDigest, COMPRESSION);
147✔
2138
    } else {
2139
      int32_t code = tdigestMerge(pTDigest, pInput->pTDigest);
2✔
2140
      if (TSDB_CODE_SUCCESS != code) {
2!
2141
        return code;
×
2142
      }
2143
    }
2144
  } else {
2145
    buildHistogramInfo(pInput);
8,258✔
2146
    if (pInput->pHisto->numOfElems <= 0) {
8,258✔
2147
      return TSDB_CODE_SUCCESS;
142✔
2148
    }
2149

2150
    if (hasRes) {
8,116✔
2151
      *hasRes = true;
8,114✔
2152
    }
2153

2154
    buildHistogramInfo(pOutput);
8,116✔
2155
    SHistogramInfo* pHisto = pOutput->pHisto;
8,116✔
2156

2157
    if (pHisto->numOfElems <= 0) {
8,116✔
2158
      (void)memcpy(pHisto, pInput->pHisto, sizeof(SHistogramInfo) + sizeof(SHistBin) * (MAX_HISTOGRAM_BIN + 1));
7,674✔
2159
      pHisto->elems = (SHistBin*)((char*)pHisto + sizeof(SHistogramInfo));
7,674✔
2160

2161
      qDebug("%s merge histo, total:%" PRId64 ", entry:%d, %p", __FUNCTION__, pHisto->numOfElems, pHisto->numOfEntries,
7,674✔
2162
             pHisto);
2163
    } else {
2164
      pHisto->elems = (SHistBin*)((char*)pHisto + sizeof(SHistogramInfo));
442✔
2165
      qDebug("%s input histogram, elem:%" PRId64 ", entry:%d, %p", __FUNCTION__, pHisto->numOfElems,
442✔
2166
             pHisto->numOfEntries, pInput->pHisto);
2167

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

2177
      qDebug("%s merge histo, total:%" PRId64 ", entry:%d, %p", __FUNCTION__, pHisto->numOfElems, pHisto->numOfEntries,
442✔
2178
             pHisto);
2179
      tHistogramDestroy(&pRes);
442✔
2180
    }
2181
  }
2182
  return TSDB_CODE_SUCCESS;
8,265✔
2183
}
2184

2185
int32_t apercentileFunctionMerge(SqlFunctionCtx* pCtx) {
8,346✔
2186
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
8,346✔
2187

2188
  SInputColumnInfoData* pInput = &pCtx->input;
8,346✔
2189

2190
  SColumnInfoData* pCol = pInput->pData[0];
8,346✔
2191
  if (pCol->info.type != TSDB_DATA_TYPE_BINARY) {
8,346!
2192
    return TSDB_CODE_FUNC_FUNTION_PARA_TYPE;
×
2193
  }
2194

2195
  SAPercentileInfo* pInfo = GET_ROWCELL_INTERBUF(pResInfo);
8,346✔
2196

2197
  qDebug("%s total %" PRId64 " rows will merge, %p", __FUNCTION__, pInput->numOfRows, pInfo->pHisto);
8,346✔
2198

2199
  bool    hasRes = false;
8,346✔
2200
  int32_t start = pInput->startRowIndex;
8,346✔
2201
  for (int32_t i = start; i < start + pInput->numOfRows; ++i) {
16,750✔
2202
    char* data = colDataGetData(pCol, i);
8,404!
2203

2204
    SAPercentileInfo* pInputInfo = (SAPercentileInfo*)varDataVal(data);
8,404✔
2205
    int32_t           code = apercentileTransferInfo(pInputInfo, pInfo, &hasRes);
8,404✔
2206
    if (TSDB_CODE_SUCCESS != code) {
8,404!
2207
      return code;
×
2208
    }
2209
  }
2210

2211
  if (pInfo->algo != APERCT_ALGO_TDIGEST) {
8,346✔
2212
    buildHistogramInfo(pInfo);
8,198✔
2213
    qDebug("%s after merge, total:%" PRId64 ", numOfEntry:%d, %p", __FUNCTION__, pInfo->pHisto->numOfElems,
8,198✔
2214
           pInfo->pHisto->numOfEntries, pInfo->pHisto);
2215
  }
2216

2217
  SET_VAL(pResInfo, hasRes ? 1 : 0, 1);
8,346✔
2218
  return TSDB_CODE_SUCCESS;
8,346✔
2219
}
2220

2221
int32_t apercentileFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
298,677✔
2222
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
298,677✔
2223
  SAPercentileInfo*    pInfo = (SAPercentileInfo*)GET_ROWCELL_INTERBUF(pResInfo);
298,677✔
2224

2225
  if (pInfo->algo == APERCT_ALGO_TDIGEST) {
298,677✔
2226
    buildTDigestInfo(pInfo);
11,763✔
2227
    tdigestAutoFill(pInfo->pTDigest, COMPRESSION);
11,763✔
2228
    if (pInfo->pTDigest->size > 0) {
11,764!
2229
      pInfo->result = tdigestQuantile(pInfo->pTDigest, pInfo->percent / 100);
11,764✔
2230
    } else {  // no need to free
2231
      // setNull(pCtx->pOutput, pCtx->outputType, pCtx->outputBytes);
2232
      return TSDB_CODE_SUCCESS;
×
2233
    }
2234
  } else {
2235
    buildHistogramInfo(pInfo);
286,914✔
2236
    if (pInfo->pHisto->numOfElems > 0) {
286,912✔
2237
      qDebug("%s get the final res, elements:%" PRId64 ", numOfEntry:%d, pHisto:%p, elems:%p", __FUNCTION__,
237,607✔
2238
             pInfo->pHisto->numOfElems, pInfo->pHisto->numOfEntries, pInfo->pHisto, pInfo->pHisto->elems);
2239

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

2258
  return functionFinalize(pCtx, pBlock);
298,672✔
2259
}
2260

2261
int32_t apercentilePartialFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
8,081✔
2262
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
8,081✔
2263
  SAPercentileInfo*    pInfo = (SAPercentileInfo*)GET_ROWCELL_INTERBUF(pResInfo);
8,081✔
2264

2265
  int32_t resultBytes = getApercentileMaxSize();
8,081✔
2266
  char*   res = taosMemoryCalloc(resultBytes + VARSTR_HEADER_SIZE, sizeof(char));
8,081!
2267
  if (NULL == res) {
8,081!
2268
    return terrno;
×
2269
  }
2270

2271
  if (pInfo->algo == APERCT_ALGO_TDIGEST) {
8,081✔
2272
    (void)memcpy(varDataVal(res), pInfo, resultBytes);
148✔
2273
    varDataSetLen(res, resultBytes);
148✔
2274
  } else {
2275
    (void)memcpy(varDataVal(res), pInfo, resultBytes);
7,933✔
2276
    varDataSetLen(res, resultBytes);
7,933✔
2277
  }
2278

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

2286
  int32_t code = colDataSetVal(pCol, pBlock->info.rows, res, false);
8,081✔
2287

2288
  taosMemoryFree(res);
8,081!
2289
  return code;
8,081✔
2290
}
2291

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

2296
  SResultRowEntryInfo* pSResInfo = GET_RES_INFO(pSourceCtx);
4✔
2297
  SAPercentileInfo*    pSBuf = GET_ROWCELL_INTERBUF(pSResInfo);
4✔
2298

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

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

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

2334
EFuncDataRequired firstDynDataReq(void* pRes, SDataBlockInfo* pBlockInfo) {
32,309✔
2335
  SResultRowEntryInfo* pEntry = (SResultRowEntryInfo*)pRes;
32,309✔
2336

2337
  // not initialized yet, data is required
2338
  if (pEntry == NULL) {
32,309!
2339
    return FUNC_DATA_REQUIRED_DATA_LOAD;
×
2340
  }
2341

2342
  SFirstLastRes* pResult = GET_ROWCELL_INTERBUF(pEntry);
32,309✔
2343
  if (pResult->hasResult) {
32,309✔
2344
    if (pResult->pkBytes > 0) {
30,449✔
2345
      pResult->pkData = pResult->buf + pResult->bytes;
6✔
2346
    } else {
2347
      pResult->pkData = NULL;
30,443✔
2348
    }
2349
    if (pResult->ts < pBlockInfo->window.skey) {
30,449✔
2350
      return FUNC_DATA_REQUIRED_NOT_LOAD;
29,731✔
2351
    } else if (pResult->ts == pBlockInfo->window.skey) {
718✔
2352
      if (NULL == pResult->pkData) {
199✔
2353
        return FUNC_DATA_REQUIRED_NOT_LOAD;
193✔
2354
      }
2355
      if (comparePkDataWithSValue(pResult->pkType, pResult->pkData, pBlockInfo->pks + 0, TSDB_ORDER_ASC) < 0) {
6!
2356
        return FUNC_DATA_REQUIRED_NOT_LOAD;
6✔
2357
      }
2358
    }
2359
    return FUNC_DATA_REQUIRED_DATA_LOAD;
519✔
2360
  } else {
2361
    return FUNC_DATA_REQUIRED_DATA_LOAD;
1,860✔
2362
  }
2363
}
2364

2365
EFuncDataRequired lastDynDataReq(void* pRes, SDataBlockInfo* pBlockInfo) {
13,260✔
2366
  SResultRowEntryInfo* pEntry = (SResultRowEntryInfo*)pRes;
13,260✔
2367

2368
  // not initialized yet, data is required
2369
  if (pEntry == NULL) {
13,260!
2370
    return FUNC_DATA_REQUIRED_DATA_LOAD;
×
2371
  }
2372

2373
  SFirstLastRes* pResult = GET_ROWCELL_INTERBUF(pEntry);
13,260✔
2374
  if (pResult->hasResult) {
13,260✔
2375
    if (pResult->pkBytes > 0) {
13,171✔
2376
      pResult->pkData = pResult->buf + pResult->bytes;
5✔
2377
    } else {
2378
      pResult->pkData = NULL;
13,166✔
2379
    }
2380
    if (pResult->ts > pBlockInfo->window.ekey) {
13,171✔
2381
      return FUNC_DATA_REQUIRED_NOT_LOAD;
10,785✔
2382
    } else if (pResult->ts == pBlockInfo->window.ekey && pResult->pkData) {
2,386✔
2383
      if (comparePkDataWithSValue(pResult->pkType, pResult->pkData, pBlockInfo->pks + 1, TSDB_ORDER_DESC) < 0) {
5!
2384
        return FUNC_DATA_REQUIRED_NOT_LOAD;
×
2385
      }
2386
    }
2387
    return FUNC_DATA_REQUIRED_DATA_LOAD;
2,386✔
2388
  } else {
2389
    return FUNC_DATA_REQUIRED_DATA_LOAD;
89✔
2390
  }
2391
}
2392

2393
// TODO modify it to include primary key bytes
2394
int32_t getFirstLastInfoSize(int32_t resBytes, int32_t pkBytes) { return sizeof(SFirstLastRes) + resBytes + pkBytes; }
75,392,380✔
2395

2396
bool getFirstLastFuncEnv(SFunctionNode* pFunc, SFuncExecEnv* pEnv) {
1,809,113✔
2397
  SColumnNode* pNode = (SColumnNode*)nodesListGetNode(pFunc->pParameterList, 0);
1,809,113✔
2398
  // TODO: change SFunctionNode to add pk info
2399
  int32_t pkBytes = (pFunc->hasPk) ? pFunc->pkBytes : 0;
1,810,949✔
2400
  pEnv->calcMemSize = getFirstLastInfoSize(pNode->node.resType.bytes, pkBytes);
1,810,949✔
2401
  return true;
1,811,007✔
2402
}
2403

2404
bool getSelectivityFuncEnv(SFunctionNode* pFunc, SFuncExecEnv* pEnv) {
1,195,308✔
2405
  SColumnNode* pNode = (SColumnNode*)nodesListGetNode(pFunc->pParameterList, 0);
1,195,308✔
2406
  pEnv->calcMemSize = pNode->node.resType.bytes;
1,196,600✔
2407
  return true;
1,196,600✔
2408
}
2409

2410
bool getGroupKeyFuncEnv(SFunctionNode* pFunc, SFuncExecEnv* pEnv) {
250,635✔
2411
  SColumnNode* pNode = (SColumnNode*)nodesListGetNode(pFunc->pParameterList, 0);
250,635✔
2412
  pEnv->calcMemSize = sizeof(SGroupKeyInfo) + pNode->node.resType.bytes;
250,999✔
2413
  return true;
250,999✔
2414
}
2415

2416
static FORCE_INLINE TSKEY getRowPTs(SColumnInfoData* pTsColInfo, int32_t rowIndex) {
2417
  if (pTsColInfo == NULL || pTsColInfo->pData == NULL) {
369,191,627!
2418
    return 0;
×
2419
  }
2420

2421
  return *(TSKEY*)colDataGetData(pTsColInfo, rowIndex);
369,305,935!
2422
}
2423

2424
int32_t firstLastFunctionSetup(SqlFunctionCtx* pCtx, SResultRowEntryInfo* pResInfo) {
14,015,593✔
2425
  if (pResInfo->initialized) {
14,015,593!
2426
    return TSDB_CODE_SUCCESS;
×
2427
  }
2428
  if (TSDB_CODE_SUCCESS != functionSetup(pCtx, pResInfo)) {
14,015,593!
2429
    return TSDB_CODE_FUNC_SETUP_ERROR;
×
2430
  }
2431

2432
  SFirstLastRes*        pRes = GET_ROWCELL_INTERBUF(pResInfo);
14,016,865✔
2433
  SInputColumnInfoData* pInput = &pCtx->input;
14,016,865✔
2434

2435
  pRes->nullTupleSaved = false;
14,016,865✔
2436
  pRes->nullTuplePos.pageId = -1;
14,016,865✔
2437
  return TSDB_CODE_SUCCESS;
14,016,865✔
2438
}
2439

2440
static int32_t prepareBuf(SqlFunctionCtx* pCtx) {
238,734,538✔
2441
  if (pCtx->subsidiaries.rowLen == 0) {
238,734,538✔
2442
    int32_t rowLen = 0;
641,812✔
2443
    for (int32_t j = 0; j < pCtx->subsidiaries.num; ++j) {
1,290,604✔
2444
      SqlFunctionCtx* pc = pCtx->subsidiaries.pCtx[j];
648,792✔
2445
      rowLen += pc->pExpr->base.resSchema.bytes;
648,792✔
2446
    }
2447

2448
    pCtx->subsidiaries.rowLen = rowLen + pCtx->subsidiaries.num * sizeof(bool);
641,812✔
2449
    pCtx->subsidiaries.buf = taosMemoryMalloc(pCtx->subsidiaries.rowLen);
641,812!
2450
    if (NULL == pCtx->subsidiaries.buf) {
636,691!
2451
      return terrno;
×
2452
    }
2453
  }
2454
  return TSDB_CODE_SUCCESS;
238,729,417✔
2455
}
2456

2457
static int32_t firstlastSaveTupleData(const SSDataBlock* pSrcBlock, int32_t rowIndex, SqlFunctionCtx* pCtx,
226,946,321✔
2458
                                      SFirstLastRes* pInfo, bool noElements) {
2459
  int32_t code = TSDB_CODE_SUCCESS;
226,946,321✔
2460

2461
  if (pCtx->subsidiaries.num <= 0) {
226,946,321✔
2462
    return TSDB_CODE_SUCCESS;
119,260,334✔
2463
  }
2464

2465
  if (!pInfo->hasResult) {
107,685,987✔
2466
    code = saveTupleData(pCtx, rowIndex, pSrcBlock, noElements ? &pInfo->nullTuplePos : &pInfo->pos);
85,663,306✔
2467
  } else {
2468
    code = updateTupleData(pCtx, rowIndex, pSrcBlock, &pInfo->pos);
22,022,681✔
2469
  }
2470

2471
  return code;
107,485,250✔
2472
}
2473

2474
static int32_t doSaveCurrentVal(SqlFunctionCtx* pCtx, int32_t rowIndex, int64_t currentTs, char* pkData, int32_t type,
110,611,415✔
2475
                                char* pData) {
2476
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
110,611,415✔
2477
  SFirstLastRes*       pInfo = GET_ROWCELL_INTERBUF(pResInfo);
110,611,415✔
2478

2479
  if (IS_VAR_DATA_TYPE(type)) {
110,611,415!
2480
    if (type == TSDB_DATA_TYPE_JSON) {
3,177,428!
2481
      pInfo->bytes = getJsonValueLen(pData);
×
2482
    } else {
2483
      pInfo->bytes = varDataTLen(pData);
3,177,428✔
2484
    }
2485
  }
2486

2487
  (void)memcpy(pInfo->buf, pData, pInfo->bytes);
110,611,415✔
2488
  if (pkData != NULL) {
110,611,415✔
2489
    if (IS_VAR_DATA_TYPE(pInfo->pkType)) {
30,118!
2490
      if (pInfo->pkType == TSDB_DATA_TYPE_JSON) {
24!
2491
        pInfo->pkBytes = getJsonValueLen(pkData);
×
2492
      } else {
2493
        pInfo->pkBytes = varDataTLen(pkData);
24✔
2494
      }
2495
    }
2496
    (void)memcpy(pInfo->buf + pInfo->bytes, pkData, pInfo->pkBytes);
30,118✔
2497
    pInfo->pkData = pInfo->buf + pInfo->bytes;
30,118✔
2498
  }
2499

2500
  pInfo->ts = currentTs;
110,611,415✔
2501
  int32_t code = firstlastSaveTupleData(pCtx->pSrcBlock, rowIndex, pCtx, pInfo, false);
110,611,415✔
2502
  if (code != TSDB_CODE_SUCCESS) {
110,588,010!
2503
    return code;
×
2504
  }
2505

2506
  pInfo->hasResult = true;
110,588,010✔
2507
  return TSDB_CODE_SUCCESS;
110,588,010✔
2508
}
2509

2510
// This ordinary first function does not care if current scan is ascending order or descending order scan
2511
// the OPTIMIZED version of first function will only handle the ascending order scan
2512
int32_t firstFunction(SqlFunctionCtx* pCtx) {
56,774,853✔
2513
  int32_t numOfElems = 0;
56,774,853✔
2514

2515
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
56,774,853✔
2516
  SFirstLastRes*       pInfo = GET_ROWCELL_INTERBUF(pResInfo);
56,774,853✔
2517

2518
  SInputColumnInfoData* pInput = &pCtx->input;
56,774,853✔
2519
  SColumnInfoData*      pInputCol = pInput->pData[0];
56,774,853✔
2520

2521
  pInfo->bytes = pInputCol->info.bytes;
56,774,853✔
2522

2523
  if (IS_NULL_TYPE(pInputCol->info.type)) {
56,774,853✔
2524
    return TSDB_CODE_SUCCESS;
4,806✔
2525
  }
2526

2527
  SColumnInfoData* pkCol = pInput->pPrimaryKey;
56,770,047✔
2528
  pInfo->pkType = -1;
56,770,047✔
2529
  __compar_fn_t pkCompareFn = NULL;
56,770,047✔
2530
  if (pCtx->hasPrimaryKey) {
56,770,047✔
2531
    pInfo->pkType = pkCol->info.type;
51✔
2532
    pInfo->pkBytes = pkCol->info.bytes;
51✔
2533
    pkCompareFn = getKeyComparFunc(pInfo->pkType, TSDB_ORDER_ASC);
51✔
2534
  }
2535

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

2548
  SColumnDataAgg* pColAgg = (pInput->colDataSMAIsSet) ? pInput->pColumnDataAgg[0] : NULL;
56,822,064!
2549

2550
  TSKEY startKey = getRowPTs(pInput->pPTS, 0);
56,822,064!
2551
  TSKEY endKey = getRowPTs(pInput->pPTS, pInput->totalRows - 1);
56,822,064!
2552

2553
  int32_t blockDataOrder = (startKey <= endKey) ? TSDB_ORDER_ASC : TSDB_ORDER_DESC;
56,822,064✔
2554

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

2566
    for (int32_t i = pInput->startRowIndex; i < pInput->startRowIndex + pInput->numOfRows; ++i) {
2567
      if (pInputCol->hasNull && colDataIsNull(pInputCol, pInput->totalRows, i, pColAgg)) {
2568
        continue;
2569
      }
2570

2571
      numOfElems++;
2572

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

2589
    for (int32_t i = pInput->numOfRows + pInput->startRowIndex - 1; i >= pInput->startRowIndex; --i) {
2590
      if (pInputCol->hasNull && colDataIsNull(pInputCol, pInput->totalRows, i, pColAgg)) {
2591
        continue;
2592
      }
2593

2594
      numOfElems++;
2595

2596
      char* data = colDataGetData(pInputCol, i);
2597
      TSKEY cts = getRowPTs(pInput->pPTS, i);
2598

2599
      if (pResInfo->numOfRes == 0 || pInfo->ts > cts) {
2600
        doSaveCurrentVal(pCtx, i, cts, pInputCol->info.type, data);
2601
        break;
2602
      }
2603
    }
2604
  }
2605
#else
2606
  int64_t* pts = (int64_t*)pInput->pPTS->pData;
56,822,064✔
2607

2608
  int     from = -1;
56,822,064✔
2609
  int32_t i = -1;
56,822,064✔
2610
  while (funcInputGetNextRowIndex(pInput, from, true, &i, &from)) {
179,321,996✔
2611
    if (pInputCol->hasNull && colDataIsNull(pInputCol, pInput->totalRows, i, pColAgg)) {
163,445,832!
2612
      continue;
2,318,042✔
2613
    }
2614

2615
    numOfElems++;
120,148,085✔
2616
    char* data = colDataGetData(pInputCol, i);
120,148,085!
2617
    char* pkData = NULL;
120,148,085✔
2618
    if (pCtx->hasPrimaryKey) {
120,148,085✔
2619
      pkData = colDataGetData(pkCol, i);
153!
2620
    }
2621
    TSKEY cts = pts[i];
120,148,085✔
2622
    if (pResInfo->numOfRes == 0 || pInfo->ts > cts ||
120,148,085✔
2623
        (pInfo->ts == cts && pkCompareFn && pkCompareFn(pkData, pInfo->pkData) < 0)) {
74,550,636!
2624
      int32_t code = doSaveCurrentVal(pCtx, i, cts, pkData, pInputCol->info.type, data);
45,597,449✔
2625
      if (code != TSDB_CODE_SUCCESS) {
45,631,254!
2626
        return code;
×
2627
      }
2628
      pResInfo->numOfRes = 1;
45,631,254✔
2629
    }
2630
  }
2631
#endif
2632

2633
  if (numOfElems == 0) {
56,475,698✔
2634
    // save selectivity value for column consisted of all null values
2635
    int32_t code = firstlastSaveTupleData(pCtx->pSrcBlock, pInput->startRowIndex, pCtx, pInfo, !pInfo->nullTupleSaved);
49,459✔
2636
    if (code != TSDB_CODE_SUCCESS) {
49,459!
2637
      return code;
×
2638
    }
2639
    pInfo->nullTupleSaved = true;
49,459✔
2640
  }
2641
  SET_VAL(pResInfo, numOfElems, 1);
56,475,698✔
2642
  return TSDB_CODE_SUCCESS;
56,475,698✔
2643
}
2644

2645
int32_t lastFunction(SqlFunctionCtx* pCtx) {
56,532,489✔
2646
  int32_t numOfElems = 0;
56,532,489✔
2647

2648
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
56,532,489✔
2649
  SFirstLastRes*       pInfo = GET_ROWCELL_INTERBUF(pResInfo);
56,532,489✔
2650

2651
  SInputColumnInfoData* pInput = &pCtx->input;
56,532,489✔
2652
  SColumnInfoData*      pInputCol = pInput->pData[0];
56,532,489✔
2653

2654
  int32_t type = pInputCol->info.type;
56,532,489✔
2655
  int32_t bytes = pInputCol->info.bytes;
56,532,489✔
2656
  pInfo->bytes = bytes;
56,532,489✔
2657

2658
  if (IS_NULL_TYPE(type)) {
56,532,489✔
2659
    return TSDB_CODE_SUCCESS;
4,807✔
2660
  }
2661

2662
  SColumnInfoData* pkCol = pInput->pPrimaryKey;
56,527,682✔
2663
  pInfo->pkType = -1;
56,527,682✔
2664
  __compar_fn_t pkCompareFn = NULL;
56,527,682✔
2665
  if (pCtx->hasPrimaryKey) {
56,527,682✔
2666
    pInfo->pkType = pkCol->info.type;
30,067✔
2667
    pInfo->pkBytes = pkCol->info.bytes;
30,067✔
2668
    pkCompareFn = getKeyComparFunc(pInfo->pkType, TSDB_ORDER_DESC);
30,067✔
2669
  }
2670

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

2683
  SColumnDataAgg* pColAgg = (pInput->colDataSMAIsSet) ? pInput->pColumnDataAgg[0] : NULL;
56,638,936!
2684

2685
  TSKEY startKey = getRowPTs(pInput->pPTS, 0);
56,638,936!
2686
  TSKEY endKey = getRowPTs(pInput->pPTS, pInput->totalRows - 1);
56,638,936!
2687

2688
  int32_t blockDataOrder = (startKey <= endKey) ? TSDB_ORDER_ASC : TSDB_ORDER_DESC;
56,638,936✔
2689

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

2698
      numOfElems++;
2699

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

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

2714
      numOfElems++;
2715

2716
      char* data = colDataGetData(pInputCol, i);
2717
      TSKEY cts = getRowPTs(pInput->pPTS, i);
2718
      if (pResInfo->numOfRes == 0 || pInfo->ts < cts) {
2719
        doSaveCurrentVal(pCtx, i, cts, type, data);
2720
      }
2721
      break;
2722
    }
2723
  }
2724
#else
2725
  int64_t* pts = (int64_t*)pInput->pPTS->pData;
56,638,936✔
2726

2727
#if 0
2728
    for (int32_t i = pInput->startRowIndex; i < pInput->numOfRows + pInput->startRowIndex; ++i) {
2729
      if (pInputCol->hasNull && colDataIsNull(pInputCol, pInput->totalRows, i, pColAgg)) {
2730
        continue;
2731
      }
2732

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

2742
  // todo refactor
2743
  if (!pInputCol->hasNull && !pCtx->hasPrimaryKey) {
90,155,410✔
2744
    numOfElems = 1;
33,635,376✔
2745

2746
    int32_t round = pInput->numOfRows >> 2;
33,635,376✔
2747
    int32_t reminder = pInput->numOfRows & 0x03;
33,635,376✔
2748

2749
    for (int32_t i = pInput->startRowIndex, tick = 0; tick < round; i += 4, tick += 1) {
51,456,074✔
2750
      int64_t cts = pts[i];
17,820,571✔
2751
      int32_t chosen = i;
17,820,571✔
2752

2753
      if (cts < pts[i + 1]) {
17,820,571✔
2754
        cts = pts[i + 1];
4,851,034✔
2755
        chosen = i + 1;
4,851,034✔
2756
      }
2757

2758
      if (cts < pts[i + 2]) {
17,820,571✔
2759
        cts = pts[i + 2];
4,851,557✔
2760
        chosen = i + 2;
4,851,557✔
2761
      }
2762

2763
      if (cts < pts[i + 3]) {
17,820,571✔
2764
        cts = pts[i + 3];
4,851,790✔
2765
        chosen = i + 3;
4,851,790✔
2766
      }
2767

2768
      if (pResInfo->numOfRes == 0 || pInfo->ts < cts) {
17,820,571✔
2769
        char*   data = colDataGetData(pInputCol, chosen);
4,781,147!
2770
        int32_t code = doSaveCurrentVal(pCtx, i, cts, NULL, type, data);
4,781,147✔
2771
        if (code != TSDB_CODE_SUCCESS) {
4,781,274!
2772
          return code;
×
2773
        }
2774
        pResInfo->numOfRes = 1;
4,781,274✔
2775
      }
2776
    }
2777

2778
    for (int32_t i = pInput->startRowIndex + round * 4; i < pInput->startRowIndex + pInput->numOfRows; ++i) {
76,706,314✔
2779
      if (pResInfo->numOfRes == 0 || pInfo->ts < pts[i]) {
43,189,840✔
2780
        char*   data = colDataGetData(pInputCol, i);
25,358,540!
2781
        int32_t code = doSaveCurrentVal(pCtx, i, pts[i], NULL, type, data);
25,358,540✔
2782
        if (code != TSDB_CODE_SUCCESS) {
25,239,511!
2783
          return code;
×
2784
        }
2785
        pResInfo->numOfRes = 1;
25,239,511✔
2786
      }
2787
    }
2788
  } else {
2789
    int     from = -1;
23,003,560✔
2790
    int32_t i = -1;
23,003,560✔
2791
    while (funcInputGetNextRowIndex(pInput, from, false, &i, &from)) {
246,178,166✔
2792
      if (colDataIsNull(pInputCol, pInput->totalRows, i, pColAgg)) {
446,379,288✔
2793
        continue;
9,342,443✔
2794
      }
2795

2796
      numOfElems++;
213,847,201✔
2797
      char* pkData = NULL;
213,847,201✔
2798
      if (pCtx->hasPrimaryKey) {
213,847,201✔
2799
        pkData = colDataGetData(pkCol, i);
100,000,193!
2800
      }
2801
      if (pResInfo->numOfRes == 0 || pInfo->ts < pts[i] ||
213,847,201✔
2802
          (pInfo->ts == pts[i] && pkCompareFn && pkCompareFn(pkData, pInfo->pkData) < 0)) {
179,146,999!
2803
        char*   data = colDataGetData(pInputCol, i);
34,900,895!
2804
        int32_t code = doSaveCurrentVal(pCtx, i, pts[i], pkData, type, data);
34,900,895✔
2805
        if (code != TSDB_CODE_SUCCESS) {
34,885,857!
2806
          return code;
×
2807
        }
2808
        pResInfo->numOfRes = 1;
34,885,857✔
2809
      }
2810
    }
2811
  }
2812
#endif
2813

2814
#endif
2815

2816
  // save selectivity value for column consisted of all null values
2817
  if (numOfElems == 0) {
56,700,094✔
2818
    int32_t code = firstlastSaveTupleData(pCtx->pSrcBlock, pInput->startRowIndex, pCtx, pInfo, !pInfo->nullTupleSaved);
4,088,955✔
2819
    if (code != TSDB_CODE_SUCCESS) {
4,081,925!
2820
      return code;
×
2821
    }
2822
    pInfo->nullTupleSaved = true;
4,081,925✔
2823
  }
2824

2825
  return TSDB_CODE_SUCCESS;
56,693,064✔
2826
}
2827

2828
static bool firstLastTransferInfoImpl(SFirstLastRes* pInput, SFirstLastRes* pOutput, bool isFirst) {
69,625,084✔
2829
  if (!pInput->hasResult) {
69,625,084✔
2830
    return false;
2✔
2831
  }
2832
  __compar_fn_t pkCompareFn = NULL;
69,625,082✔
2833
  if (pInput->pkData) {
69,625,082✔
2834
    pkCompareFn = getKeyComparFunc(pInput->pkType, (isFirst) ? TSDB_ORDER_ASC : TSDB_ORDER_DESC);
52✔
2835
  }
2836
  if (pOutput->hasResult) {
69,628,224✔
2837
    if (isFirst) {
21,972,004✔
2838
      if (pInput->ts > pOutput->ts ||
9,138,923✔
2839
          (pInput->ts == pOutput->ts && pkCompareFn && pkCompareFn(pInput->pkData, pOutput->pkData) > 0)) {
8,884,528!
2840
        return false;
254,395✔
2841
      }
2842
    } else {
2843
      if (pInput->ts < pOutput->ts ||
12,833,081✔
2844
          (pInput->ts == pOutput->ts && pkCompareFn && pkCompareFn(pInput->pkData, pOutput->pkData) > 0)) {
8,561,796!
2845
        return false;
4,271,488✔
2846
      }
2847
    }
2848
  }
2849

2850
  pOutput->isNull = pInput->isNull;
65,102,341✔
2851
  pOutput->ts = pInput->ts;
65,102,341✔
2852
  pOutput->bytes = pInput->bytes;
65,102,341✔
2853
  pOutput->pkType = pInput->pkType;
65,102,341✔
2854

2855
  (void)memcpy(pOutput->buf, pInput->buf, pOutput->bytes);
65,102,341✔
2856
  if (pInput->pkData) {
65,102,341✔
2857
    pOutput->pkBytes = pInput->pkBytes;
48✔
2858
    (void)memcpy(pOutput->buf + pOutput->bytes, pInput->pkData, pOutput->pkBytes);
48✔
2859
    pOutput->pkData = pOutput->buf + pOutput->bytes;
48✔
2860
  }
2861
  return true;
65,102,341✔
2862
}
2863

2864
static int32_t firstLastTransferInfo(SqlFunctionCtx* pCtx, SFirstLastRes* pInput, SFirstLastRes* pOutput, bool isFirst,
69,624,966✔
2865
                                     int32_t rowIndex) {
2866
  if (firstLastTransferInfoImpl(pInput, pOutput, isFirst)) {
69,624,966✔
2867
    int32_t code = firstlastSaveTupleData(pCtx->pSrcBlock, rowIndex, pCtx, pOutput, pOutput->nullTupleSaved);
65,102,077✔
2868
    if (TSDB_CODE_SUCCESS != code) {
65,091,135!
2869
      return code;
×
2870
    }
2871
    pOutput->hasResult = true;
65,091,135✔
2872
  }
2873
  return TSDB_CODE_SUCCESS;
69,613,643✔
2874
}
2875

2876
static int32_t firstLastFunctionMergeImpl(SqlFunctionCtx* pCtx, bool isFirstQuery) {
48,242,211✔
2877
  SInputColumnInfoData* pInput = &pCtx->input;
48,242,211✔
2878
  SColumnInfoData*      pCol = pInput->pData[0];
48,242,211✔
2879

2880
  if (IS_NULL_TYPE(pCol->info.type)) {
48,242,211!
2881
    SET_VAL(GET_RES_INFO(pCtx), 0, 1);
×
2882
    return TSDB_CODE_SUCCESS;
×
2883
  }
2884

2885
  if (pCol->info.type != TSDB_DATA_TYPE_BINARY) {
48,242,211!
2886
    return TSDB_CODE_FUNC_FUNTION_PARA_TYPE;
×
2887
  }
2888

2889
  SFirstLastRes* pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
48,242,211✔
2890

2891
  int32_t start = pInput->startRowIndex;
48,242,211✔
2892
  int32_t numOfElems = 0;
48,242,211✔
2893

2894
  for (int32_t i = start; i < start + pInput->numOfRows; ++i) {
120,146,180✔
2895
    if (colDataIsNull_s(pCol, i)) {
143,843,216✔
2896
      continue;
2,291,249✔
2897
    }
2898
    char*          data = colDataGetData(pCol, i);
69,630,359!
2899
    SFirstLastRes* pInputInfo = (SFirstLastRes*)varDataVal(data);
69,630,359✔
2900
    if (pCtx->hasPrimaryKey) {
69,630,359✔
2901
      pInputInfo->pkData = pInputInfo->buf + pInputInfo->bytes;
52✔
2902
    } else {
2903
      pInputInfo->pkData = NULL;
69,630,307✔
2904
    }
2905

2906
    int32_t code = firstLastTransferInfo(pCtx, pInputInfo, pInfo, isFirstQuery, i);
69,630,359✔
2907
    if (code != TSDB_CODE_SUCCESS) {
69,612,720!
2908
      return code;
×
2909
    }
2910
    if (!numOfElems) {
69,612,720✔
2911
      numOfElems = pInputInfo->hasResult ? 1 : 0;
48,224,059✔
2912
    }
2913
  }
2914

2915
  if (numOfElems == 0) {
48,224,572✔
2916
    int32_t code = firstlastSaveTupleData(pCtx->pSrcBlock, pInput->startRowIndex, pCtx, pInfo, !pInfo->nullTupleSaved);
13,945✔
2917
    if (code != TSDB_CODE_SUCCESS) {
13,945!
2918
      return code;
×
2919
    }
2920
    pInfo->nullTupleSaved = true;
13,945✔
2921
  }
2922

2923
  SET_VAL(GET_RES_INFO(pCtx), numOfElems, 1);
48,224,572✔
2924
  return TSDB_CODE_SUCCESS;
48,224,572✔
2925
}
2926

2927
int32_t firstFunctionMerge(SqlFunctionCtx* pCtx) { return firstLastFunctionMergeImpl(pCtx, true); }
13,369,839✔
2928

2929
int32_t lastFunctionMerge(SqlFunctionCtx* pCtx) { return firstLastFunctionMergeImpl(pCtx, false); }
34,880,690✔
2930

2931
int32_t firstLastFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
92,604,048✔
2932
  int32_t          code = TSDB_CODE_SUCCESS;
92,604,048✔
2933
  int32_t          slotId = pCtx->pExpr->base.resSchema.slotId;
92,604,048✔
2934
  SColumnInfoData* pCol = taosArrayGet(pBlock->pDataBlock, slotId);
92,604,048✔
2935
  if (NULL == pCol) {
92,552,200!
2936
    return TSDB_CODE_OUT_OF_RANGE;
×
2937
  }
2938

2939
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
92,552,200✔
2940
  pResInfo->isNullRes = (pResInfo->numOfRes == 0) ? 1 : 0;
92,552,200✔
2941

2942
  SFirstLastRes* pRes = GET_ROWCELL_INTERBUF(pResInfo);
92,552,200✔
2943

2944
  if (pResInfo->isNullRes) {
92,552,200✔
2945
    colDataSetNULL(pCol, pBlock->info.rows);
47,653✔
2946
    return setSelectivityValue(pCtx, pBlock, &pRes->nullTuplePos, pBlock->info.rows);
47,653✔
2947
  }
2948
  code = colDataSetVal(pCol, pBlock->info.rows, pRes->buf, pRes->isNull || pResInfo->isNullRes);
92,504,547!
2949
  if (TSDB_CODE_SUCCESS != code) {
92,349,566!
2950
    return code;
×
2951
  }
2952

2953
  // handle selectivity
2954
  code = setSelectivityValue(pCtx, pBlock, &pRes->pos, pBlock->info.rows);
92,349,566✔
2955

2956
  return code;
92,330,668✔
2957
}
2958

2959
int32_t firstLastPartialFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
73,572,689✔
2960
  int32_t code = TSDB_CODE_SUCCESS;
73,572,689✔
2961

2962
  SResultRowEntryInfo* pEntryInfo = GET_RES_INFO(pCtx);
73,572,689✔
2963
  SFirstLastRes*       pRes = GET_ROWCELL_INTERBUF(pEntryInfo);
73,572,689✔
2964

2965
  int32_t resultBytes = getFirstLastInfoSize(pRes->bytes, pRes->pkBytes);
73,572,689✔
2966

2967
  // todo check for failure
2968
  char* res = taosMemoryCalloc(resultBytes + VARSTR_HEADER_SIZE, sizeof(char));
73,517,423!
2969
  if (NULL == res) {
74,206,490!
2970
    return terrno;
×
2971
  }
2972
  (void)memcpy(varDataVal(res), pRes, resultBytes);
74,206,490✔
2973

2974
  varDataSetLen(res, resultBytes);
74,206,490✔
2975

2976
  int32_t          slotId = pCtx->pExpr->base.resSchema.slotId;
74,206,490✔
2977
  SColumnInfoData* pCol = taosArrayGet(pBlock->pDataBlock, slotId);
74,206,490✔
2978
  if (NULL == pCol) {
73,899,421!
2979
    taosMemoryFree(res);
×
2980
    return TSDB_CODE_OUT_OF_RANGE;
×
2981
  }
2982

2983
  if (pEntryInfo->numOfRes == 0) {
73,934,604✔
2984
    colDataSetNULL(pCol, pBlock->info.rows);
2,382,476!
2985
    code = setSelectivityValue(pCtx, pBlock, &pRes->nullTuplePos, pBlock->info.rows);
2,382,476✔
2986
  } else {
2987
    code = colDataSetVal(pCol, pBlock->info.rows, res, false);
71,552,128✔
2988
    if (TSDB_CODE_SUCCESS != code) {
70,984,171!
2989
      taosMemoryFree(res);
×
2990
      return code;
×
2991
    }
2992
    code = setSelectivityValue(pCtx, pBlock, &pRes->pos, pBlock->info.rows);
70,984,171✔
2993
  }
2994
  taosMemoryFree(res);
73,268,724!
2995
  return code;
74,111,955✔
2996
}
2997

2998
int32_t lastCombine(SqlFunctionCtx* pDestCtx, SqlFunctionCtx* pSourceCtx) {
3✔
2999
  SResultRowEntryInfo* pDResInfo = GET_RES_INFO(pDestCtx);
3✔
3000
  SFirstLastRes*       pDBuf = GET_ROWCELL_INTERBUF(pDResInfo);
3✔
3001
  int32_t              bytes = pDBuf->bytes;
3✔
3002

3003
  SResultRowEntryInfo* pSResInfo = GET_RES_INFO(pSourceCtx);
3✔
3004
  SFirstLastRes*       pSBuf = GET_ROWCELL_INTERBUF(pSResInfo);
3✔
3005

3006
  pDBuf->hasResult = firstLastTransferInfoImpl(pSBuf, pDBuf, false);
3✔
3007
  pDResInfo->numOfRes = TMAX(pDResInfo->numOfRes, pSResInfo->numOfRes);
3✔
3008
  pDResInfo->isNullRes &= pSResInfo->isNullRes;
3✔
3009
  return TSDB_CODE_SUCCESS;
3✔
3010
}
3011

3012
static int32_t doSaveLastrow(SqlFunctionCtx* pCtx, char* pData, int32_t rowIndex, int64_t cts, SFirstLastRes* pInfo) {
47,240,687✔
3013
  SInputColumnInfoData* pInput = &pCtx->input;
47,240,687✔
3014
  SColumnInfoData*      pInputCol = pInput->pData[0];
47,240,687✔
3015
  SColumnInfoData*      pkCol = pInput->pPrimaryKey;
47,240,687✔
3016

3017
  if (colDataIsNull_s(pInputCol, rowIndex)) {
94,481,374✔
3018
    pInfo->isNull = true;
2,206✔
3019
  } else {
3020
    pInfo->isNull = false;
47,238,481✔
3021

3022
    if (IS_VAR_DATA_TYPE(pInputCol->info.type)) {
47,238,481!
3023
      if (pInputCol->info.type == TSDB_DATA_TYPE_JSON) {
48,228!
3024
        pInfo->bytes = getJsonValueLen(pData);
×
3025
      } else {
3026
        pInfo->bytes = varDataTLen(pData);
48,228✔
3027
      }
3028
    }
3029

3030
    (void)memcpy(pInfo->buf, pData, pInfo->bytes);
47,238,481✔
3031
  }
3032

3033
  if (pCtx->hasPrimaryKey && !colDataIsNull_s(pkCol, rowIndex)) {
47,240,763!
3034
    char* pkData = colDataGetData(pkCol, rowIndex);
76!
3035
    if (IS_VAR_DATA_TYPE(pInfo->pkType)) {
76!
3036
      if (pInfo->pkType == TSDB_DATA_TYPE_JSON) {
12!
3037
        pInfo->pkBytes = getJsonValueLen(pkData);
×
3038
      } else {
3039
        pInfo->pkBytes = varDataTLen(pkData);
12✔
3040
      }
3041
    }
3042
    (void)memcpy(pInfo->buf + pInfo->bytes, pkData, pInfo->pkBytes);
76✔
3043
    pInfo->pkData = pInfo->buf + pInfo->bytes;
76✔
3044
  }
3045
  pInfo->ts = cts;
47,240,687✔
3046
  int32_t code = firstlastSaveTupleData(pCtx->pSrcBlock, rowIndex, pCtx, pInfo, false);
47,240,687✔
3047
  if (code != TSDB_CODE_SUCCESS) {
47,234,712!
3048
    return code;
×
3049
  }
3050

3051
  pInfo->hasResult = true;
47,234,712✔
3052

3053
  return TSDB_CODE_SUCCESS;
47,234,712✔
3054
}
3055

3056
int32_t lastRowFunction(SqlFunctionCtx* pCtx) {
47,256,522✔
3057
  int32_t numOfElems = 0;
47,256,522✔
3058

3059
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
47,256,522✔
3060
  SFirstLastRes*       pInfo = GET_ROWCELL_INTERBUF(pResInfo);
47,256,522✔
3061

3062
  SInputColumnInfoData* pInput = &pCtx->input;
47,256,522✔
3063
  SColumnInfoData*      pInputCol = pInput->pData[0];
47,256,522✔
3064

3065
  int32_t type = pInputCol->info.type;
47,256,522✔
3066
  int32_t bytes = pInputCol->info.bytes;
47,256,522✔
3067
  pInfo->bytes = bytes;
47,256,522✔
3068

3069
  if (IS_NULL_TYPE(type)) {
47,256,522✔
3070
    return TSDB_CODE_SUCCESS;
24✔
3071
  }
3072
  SColumnInfoData* pkCol = pInput->pPrimaryKey;
47,256,498✔
3073
  pInfo->pkType = -1;
47,256,498✔
3074
  __compar_fn_t pkCompareFn = NULL;
47,256,498✔
3075
  if (pCtx->hasPrimaryKey) {
47,256,498✔
3076
    pInfo->pkType = pkCol->info.type;
57✔
3077
    pInfo->pkBytes = pkCol->info.bytes;
57✔
3078
    pkCompareFn = getKeyComparFunc(pInfo->pkType, TSDB_ORDER_DESC);
57✔
3079
  }
3080
  TSKEY startKey = getRowPTs(pInput->pPTS, 0);
47,261,306!
3081
  TSKEY endKey = getRowPTs(pInput->pPTS, pInput->totalRows - 1);
47,261,306!
3082

3083
  if (pCtx->order == TSDB_ORDER_ASC && !pCtx->hasPrimaryKey) {
47,261,306!
3084
    for (int32_t i = pInput->numOfRows + pInput->startRowIndex - 1; i >= pInput->startRowIndex; --i) {
45,560,089!
3085
      bool  isNull = colDataIsNull(pInputCol, pInput->numOfRows, i, NULL);
22,781,803✔
3086
      char* data = isNull ? NULL : colDataGetData(pInputCol, i);
22,781,803!
3087
      TSKEY cts = getRowPTs(pInput->pPTS, i);
22,781,803!
3088
      numOfElems++;
22,781,803✔
3089

3090
      if (pResInfo->numOfRes == 0 || pInfo->ts < cts) {
22,781,803✔
3091
        int32_t code = doSaveLastrow(pCtx, data, i, cts, pInfo);
22,601,497✔
3092
        if (code != TSDB_CODE_SUCCESS) return code;
22,598,564!
3093
      }
3094

3095
      break;
22,778,870✔
3096
    }
3097
  } else if (!pCtx->hasPrimaryKey && pCtx->order == TSDB_ORDER_DESC) {
24,480,087!
3098
    // the optimized version only valid if all tuples in one block are monotonious increasing or descreasing.
3099
    // this assumption is NOT always works if project operator exists in downstream.
3100
    for (int32_t i = pInput->startRowIndex; i < pInput->numOfRows + pInput->startRowIndex; ++i) {
48,984,701!
3101
      bool  isNull = colDataIsNull(pInputCol, pInput->numOfRows, i, NULL);
24,493,893✔
3102
      char* data = isNull ? NULL : colDataGetData(pInputCol, i);
24,493,893!
3103
      TSKEY cts = getRowPTs(pInput->pPTS, i);
24,493,893!
3104
      numOfElems++;
24,493,893✔
3105

3106
      if (pResInfo->numOfRes == 0 || pInfo->ts < cts) {
24,493,893✔
3107
        int32_t code = doSaveLastrow(pCtx, data, i, cts, pInfo);
24,351,141✔
3108
        if (code != TSDB_CODE_SUCCESS) return code;
24,349,460!
3109
      }
3110
      break;
24,492,212✔
3111
    }
3112
  } else {
3113
    int64_t* pts = (int64_t*)pInput->pPTS->pData;
×
3114
    int      from = -1;
×
3115
    int32_t  i = -1;
×
3116
    while (funcInputGetNextRowIndex(pInput, from, false, &i, &from)) {
830,601✔
3117
      bool  isNull = colDataIsNull(pInputCol, pInput->numOfRows, i, NULL);
842,999✔
3118
      char* data = isNull ? NULL : colDataGetData(pInputCol, i);
842,999!
3119
      TSKEY cts = pts[i];
842,999✔
3120

3121
      numOfElems++;
842,999✔
3122
      char* pkData = NULL;
842,999✔
3123
      if (pCtx->hasPrimaryKey) {
842,999✔
3124
        pkData = colDataGetData(pkCol, i);
171!
3125
      }
3126
      if (pResInfo->numOfRes == 0 || pInfo->ts < cts ||
842,999✔
3127
          (pInfo->ts == pts[i] && pkCompareFn && pkCompareFn(pkData, pInfo->pkData) < 0)) {
552,574!
3128
        int32_t code = doSaveLastrow(pCtx, data, i, cts, pInfo);
290,431✔
3129
        if (code != TSDB_CODE_SUCCESS) {
290,435!
3130
          return code;
×
3131
        }
3132
        pResInfo->numOfRes = 1;
290,435✔
3133
      }
3134
    }
3135
  }
3136

3137
  SET_VAL(pResInfo, numOfElems, 1);
47,270,499!
3138
  return TSDB_CODE_SUCCESS;
47,270,499✔
3139
}
3140

3141
bool getDiffFuncEnv(SFunctionNode* UNUSED_PARAM(pFunc), SFuncExecEnv* pEnv) {
38,359✔
3142
  pEnv->calcMemSize = sizeof(SDiffInfo);
38,359✔
3143
  return true;
38,359✔
3144
}
3145

3146
int32_t diffFunctionSetup(SqlFunctionCtx* pCtx, SResultRowEntryInfo* pResInfo) {
1,557,863✔
3147
  if (pResInfo->initialized) {
1,557,863✔
3148
    return TSDB_CODE_SUCCESS;
1,477,650✔
3149
  }
3150
  if (TSDB_CODE_SUCCESS != functionSetup(pCtx, pResInfo)) {
80,213!
3151
    return TSDB_CODE_FUNC_SETUP_ERROR;
×
3152
  }
3153
  SDiffInfo* pDiffInfo = GET_ROWCELL_INTERBUF(pResInfo);
80,213✔
3154
  pDiffInfo->hasPrev = false;
80,213✔
3155
  pDiffInfo->isFirstRow = true;
80,213✔
3156
  pDiffInfo->prev.i64 = 0;
80,213✔
3157
  pDiffInfo->prevTs = -1;
80,213✔
3158
  if (pCtx->numOfParams > 1) {
80,213!
3159
    pDiffInfo->ignoreOption = pCtx->param[1].param.i;  // TODO set correct param
80,213✔
3160
  } else {
3161
    pDiffInfo->ignoreOption = 0;
×
3162
  }
3163
  return TSDB_CODE_SUCCESS;
80,213✔
3164
}
3165

3166
static int32_t doSetPrevVal(SDiffInfo* pDiffInfo, int32_t type, const char* pv, int64_t ts) {
740,611✔
3167
  switch (type) {
740,611!
3168
    case TSDB_DATA_TYPE_BOOL:
28✔
3169
      pDiffInfo->prev.i64 = *(bool*)pv ? 1 : 0;
28✔
3170
      break;
28✔
3171
    case TSDB_DATA_TYPE_UTINYINT:
316✔
3172
    case TSDB_DATA_TYPE_TINYINT:
3173
      pDiffInfo->prev.i64 = *(int8_t*)pv;
316✔
3174
      break;
316✔
3175
    case TSDB_DATA_TYPE_UINT:
479,891✔
3176
    case TSDB_DATA_TYPE_INT:
3177
      pDiffInfo->prev.i64 = *(int32_t*)pv;
479,891✔
3178
      break;
479,891✔
3179
    case TSDB_DATA_TYPE_USMALLINT:
102,435✔
3180
    case TSDB_DATA_TYPE_SMALLINT:
3181
      pDiffInfo->prev.i64 = *(int16_t*)pv;
102,435✔
3182
      break;
102,435✔
3183
    case TSDB_DATA_TYPE_TIMESTAMP:
286✔
3184
    case TSDB_DATA_TYPE_UBIGINT:
3185
    case TSDB_DATA_TYPE_BIGINT:
3186
      pDiffInfo->prev.i64 = *(int64_t*)pv;
286✔
3187
      break;
286✔
3188
    case TSDB_DATA_TYPE_FLOAT:
238✔
3189
      pDiffInfo->prev.d64 = *(float*)pv;
238✔
3190
      break;
238✔
3191
    case TSDB_DATA_TYPE_DOUBLE:
157,417✔
3192
      pDiffInfo->prev.d64 = *(double*)pv;
157,417✔
3193
      break;
157,417✔
3194
    default:
×
3195
      return TSDB_CODE_FUNC_FUNTION_PARA_TYPE;
×
3196
  }
3197
  pDiffInfo->prevTs = ts;
740,611✔
3198
  pDiffInfo->hasPrev = true;
740,611✔
3199
  return TSDB_CODE_SUCCESS;
740,611✔
3200
}
3201

3202
static bool diffIsNegtive(SDiffInfo* pDiffInfo, int32_t type, const char* pv) {
2,867,282✔
3203
  switch (type) {
2,867,282!
3204
    case TSDB_DATA_TYPE_UINT: {
×
3205
      int64_t v = *(uint32_t*)pv;
×
3206
      return v < pDiffInfo->prev.i64;
×
3207
    }
3208
    case TSDB_DATA_TYPE_INT: {
1,606,578✔
3209
      int64_t v = *(int32_t*)pv;
1,606,578✔
3210
      return v < pDiffInfo->prev.i64;
1,606,578✔
3211
    }
3212
    case TSDB_DATA_TYPE_BOOL: {
×
3213
      int64_t v = *(bool*)pv;
×
3214
      return v < pDiffInfo->prev.i64;
×
3215
    }
3216
    case TSDB_DATA_TYPE_UTINYINT: {
×
3217
      int64_t v = *(uint8_t*)pv;
×
3218
      return v < pDiffInfo->prev.i64;
×
3219
    }
3220
    case TSDB_DATA_TYPE_TINYINT: {
4,089✔
3221
      int64_t v = *(int8_t*)pv;
4,089✔
3222
      return v < pDiffInfo->prev.i64;
4,089✔
3223
    }
3224
    case TSDB_DATA_TYPE_USMALLINT: {
×
3225
      int64_t v = *(uint16_t*)pv;
×
3226
      return v < pDiffInfo->prev.i64;
×
3227
    }
3228
    case TSDB_DATA_TYPE_SMALLINT: {
556,054✔
3229
      int64_t v = *(int16_t*)pv;
556,054✔
3230
      return v < pDiffInfo->prev.i64;
556,054✔
3231
    }
3232
    case TSDB_DATA_TYPE_UBIGINT: {
24✔
3233
      uint64_t v = *(uint64_t*)pv;
24✔
3234
      return v < (uint64_t)pDiffInfo->prev.i64;
24✔
3235
    }
3236
    case TSDB_DATA_TYPE_TIMESTAMP:
5,688✔
3237
    case TSDB_DATA_TYPE_BIGINT: {
3238
      int64_t v = *(int64_t*)pv;
5,688✔
3239
      return v < pDiffInfo->prev.i64;
5,688✔
3240
    }
3241
    case TSDB_DATA_TYPE_FLOAT: {
6,369✔
3242
      float v = *(float*)pv;
6,369✔
3243
      return v < pDiffInfo->prev.d64;
6,369✔
3244
    }
3245
    case TSDB_DATA_TYPE_DOUBLE: {
688,480✔
3246
      double v = *(double*)pv;
688,480✔
3247
      return v < pDiffInfo->prev.d64;
688,480✔
3248
    }
3249
    default:
×
3250
      return false;
×
3251
  }
3252

3253
  return false;
3254
}
3255

3256
static void tryToSetInt64(SDiffInfo* pDiffInfo, int32_t type, SColumnInfoData* pOutput, int64_t v, int32_t pos) {
1,239,454,128✔
3257
  bool isNegative = v < pDiffInfo->prev.i64;
1,239,454,128✔
3258
  if (type == TSDB_DATA_TYPE_UBIGINT) {
1,239,454,128✔
3259
    isNegative = (uint64_t)v < (uint64_t)pDiffInfo->prev.i64;
453✔
3260
  }
3261
  int64_t delta = v - pDiffInfo->prev.i64;
1,239,454,128✔
3262
  if (isNegative && ignoreNegative(pDiffInfo->ignoreOption)) {
1,239,454,128✔
3263
    colDataSetNull_f_s(pOutput, pos);
524,281✔
3264
    pOutput->hasNull = true;
524,281✔
3265
  } else {
3266
    colDataSetInt64(pOutput, pos, &delta);
1,238,929,847✔
3267
  }
3268
  pDiffInfo->prev.i64 = v;
1,239,454,128✔
3269
}
1,239,454,128✔
3270

3271
static void tryToSetDouble(SDiffInfo* pDiffInfo, SColumnInfoData* pOutput, double v, int32_t pos) {
765,805✔
3272
  double delta = v - pDiffInfo->prev.d64;
765,805✔
3273
  if (delta < 0 && ignoreNegative(pDiffInfo->ignoreOption)) {
765,805✔
3274
    colDataSetNull_f_s(pOutput, pos);
229,855✔
3275
  } else {
3276
    colDataSetDouble(pOutput, pos, &delta);
535,950✔
3277
  }
3278
  pDiffInfo->prev.d64 = v;
765,805✔
3279
}
765,805✔
3280

3281
static int32_t doHandleDiff(SDiffInfo* pDiffInfo, int32_t type, const char* pv, SColumnInfoData* pOutput, int32_t pos,
1,240,220,502✔
3282
                            int64_t ts) {
3283
  if (!pDiffInfo->hasPrev) {
1,240,220,502✔
3284
    colDataSetNull_f_s(pOutput, pos);
569✔
3285
    return doSetPrevVal(pDiffInfo, type, pv, ts);
569✔
3286
  }
3287
  pDiffInfo->prevTs = ts;
1,240,219,933✔
3288
  switch (type) {
1,240,219,933!
3289
    case TSDB_DATA_TYPE_UINT: {
411✔
3290
      int64_t v = *(uint32_t*)pv;
411✔
3291
      tryToSetInt64(pDiffInfo, type, pOutput, v, pos);
411✔
3292
      break;
411✔
3293
    }
3294
    case TSDB_DATA_TYPE_INT: {
22,658,045✔
3295
      int64_t v = *(int32_t*)pv;
22,658,045✔
3296
      tryToSetInt64(pDiffInfo, type, pOutput, v, pos);
22,658,045✔
3297
      break;
22,658,045✔
3298
    }
3299
    case TSDB_DATA_TYPE_BOOL: {
10,617✔
3300
      int64_t v = *(bool*)pv;
10,617✔
3301
      tryToSetInt64(pDiffInfo, type, pOutput, v, pos);
10,617✔
3302
      break;
10,617✔
3303
    }
3304
    case TSDB_DATA_TYPE_UTINYINT: {
405✔
3305
      int64_t v = *(uint8_t*)pv;
405✔
3306
      tryToSetInt64(pDiffInfo, type, pOutput, v, pos);
405✔
3307
      break;
405✔
3308
    }
3309
    case TSDB_DATA_TYPE_TINYINT: {
36,327✔
3310
      int64_t v = *(int8_t*)pv;
36,327✔
3311
      tryToSetInt64(pDiffInfo, type, pOutput, v, pos);
36,327✔
3312
      break;
36,327✔
3313
    }
3314
    case TSDB_DATA_TYPE_USMALLINT: {
405✔
3315
      int64_t v = *(uint16_t*)pv;
405✔
3316
      tryToSetInt64(pDiffInfo, type, pOutput, v, pos);
405✔
3317
      break;
405✔
3318
    }
3319
    case TSDB_DATA_TYPE_SMALLINT: {
490,999✔
3320
      int64_t v = *(int16_t*)pv;
490,999✔
3321
      tryToSetInt64(pDiffInfo, type, pOutput, v, pos);
490,999✔
3322
      break;
490,999✔
3323
    }
3324
    case TSDB_DATA_TYPE_TIMESTAMP:
1,216,256,919✔
3325
    case TSDB_DATA_TYPE_UBIGINT:
3326
    case TSDB_DATA_TYPE_BIGINT: {
3327
      int64_t v = *(int64_t*)pv;
1,216,256,919✔
3328
      tryToSetInt64(pDiffInfo, type, pOutput, v, pos);
1,216,256,919✔
3329
      break;
1,216,256,919✔
3330
    }
3331
    case TSDB_DATA_TYPE_FLOAT: {
45,197✔
3332
      double v = *(float*)pv;
45,197✔
3333
      tryToSetDouble(pDiffInfo, pOutput, v, pos);
45,197✔
3334
      break;
45,197✔
3335
    }
3336
    case TSDB_DATA_TYPE_DOUBLE: {
720,608✔
3337
      double v = *(double*)pv;
720,608✔
3338
      tryToSetDouble(pDiffInfo, pOutput, v, pos);
720,608✔
3339
      break;
720,608✔
3340
    }
3341
    default:
×
3342
      return TSDB_CODE_FUNC_FUNTION_PARA_TYPE;
×
3343
  }
3344
  pDiffInfo->hasPrev = true;
1,240,219,933✔
3345
  return TSDB_CODE_SUCCESS;
1,240,219,933✔
3346
}
3347

3348
// TODO: the primary key compare can be skipped for ordered pk if knonwn before
3349
// TODO: for desc ordered, pk shall select the smallest one for one ts. if across block boundaries.
3350
bool funcInputGetNextRowIndex(SInputColumnInfoData* pInput, int32_t from, bool firstOccur, int32_t* pRowIndex,
425,809,812✔
3351
                              int32_t* nextFrom) {
3352
  if (pInput->pPrimaryKey == NULL) {
425,809,812✔
3353
    if (from == -1) {
325,929,360✔
3354
      from = pInput->startRowIndex;
80,832,958✔
3355
    } else if (from >= pInput->numOfRows + pInput->startRowIndex) {
245,096,402✔
3356
      return false;
80,624,571✔
3357
    }
3358
    *pRowIndex = from;
245,304,789✔
3359
    *nextFrom = from + 1;
245,304,789✔
3360
    return true;
245,304,789✔
3361
  } else {
3362
    if (from == -1) {
99,880,452✔
3363
      from = pInput->startRowIndex;
30,175✔
3364
    } else if (from >= pInput->numOfRows + pInput->startRowIndex) {
99,850,277✔
3365
      return false;
30,175✔
3366
    }
3367
    TSKEY*           tsList = (int64_t*)pInput->pPTS->pData;
99,850,277✔
3368
    SColumnInfoData* pkCol = pInput->pPrimaryKey;
99,850,277✔
3369
    int8_t           pkType = pkCol->info.type;
99,850,277✔
3370
    int32_t          order = (firstOccur) ? TSDB_ORDER_ASC : TSDB_ORDER_DESC;
99,850,277✔
3371
    __compar_fn_t    compareFunc = getKeyComparFunc(pkType, order);
99,850,277✔
3372
    int32_t          select = from;
100,000,517✔
3373
    char*            val = colDataGetData(pkCol, select);
100,000,517!
3374
    while (from < pInput->numOfRows + pInput->startRowIndex - 1 && tsList[from + 1] == tsList[from]) {
100,001,072✔
3375
      char* val1 = colDataGetData(pkCol, from + 1);
555!
3376
      if (compareFunc(val1, val) < 0) {
555!
3377
        select = from + 1;
×
3378
        val = val1;
×
3379
      }
3380
      from = from + 1;
555✔
3381
    }
3382
    *pRowIndex = select;
100,000,517✔
3383
    *nextFrom = from + 1;
100,000,517✔
3384
    return true;
100,000,517✔
3385
  }
3386
}
3387

3388
bool getForecastConfEnv(SFunctionNode* UNUSED_PARAM(pFunc), SFuncExecEnv* pEnv) {
26✔
3389
  pEnv->calcMemSize = sizeof(float);
26✔
3390
  return true;
26✔
3391
}
3392

3393
int32_t diffResultIsNull(SqlFunctionCtx* pCtx, SFuncInputRow* pRow) {
1,241,050,000✔
3394
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
1,241,050,000✔
3395
  SDiffInfo*           pDiffInfo = GET_ROWCELL_INTERBUF(pResInfo);
1,241,050,000✔
3396

3397
  if (pRow->isDataNull || !pDiffInfo->hasPrev) {
1,241,050,000✔
3398
    return true;
168,473✔
3399
  } else if (ignoreNegative(pDiffInfo->ignoreOption)) {
1,240,881,527✔
3400
    return diffIsNegtive(pDiffInfo, pCtx->input.pData[0]->info.type, pRow->pData);
2,867,282✔
3401
  }
3402
  return false;
1,238,014,245✔
3403
}
3404

3405
bool isFirstRow(SqlFunctionCtx* pCtx, SFuncInputRow* pRow) {
1,240,374,389✔
3406
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
1,240,374,389✔
3407
  SDiffInfo*           pDiffInfo = GET_ROWCELL_INTERBUF(pResInfo);
1,240,374,389✔
3408
  return pDiffInfo->isFirstRow;
1,240,374,389✔
3409
}
3410

3411
int32_t trySetPreVal(SqlFunctionCtx* pCtx, SFuncInputRow* pRow) {
741,842✔
3412
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
741,842✔
3413
  SDiffInfo*           pDiffInfo = GET_ROWCELL_INTERBUF(pResInfo);
741,842✔
3414
  pDiffInfo->isFirstRow = false;
741,842✔
3415
  if (pRow->isDataNull) {
741,842✔
3416
    return TSDB_CODE_SUCCESS;
1,800✔
3417
  }
3418

3419
  SInputColumnInfoData* pInput = &pCtx->input;
740,042✔
3420
  SColumnInfoData*      pInputCol = pInput->pData[0];
740,042✔
3421
  int8_t                inputType = pInputCol->info.type;
740,042✔
3422

3423
  char* pv = pRow->pData;
740,042✔
3424
  return doSetPrevVal(pDiffInfo, inputType, pv, pRow->ts);
740,042✔
3425
}
3426

3427
int32_t setDoDiffResult(SqlFunctionCtx* pCtx, SFuncInputRow* pRow, int32_t pos) {
1,240,308,158✔
3428
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
1,240,308,158✔
3429
  SDiffInfo*           pDiffInfo = GET_ROWCELL_INTERBUF(pResInfo);
1,240,308,158✔
3430

3431
  SInputColumnInfoData* pInput = &pCtx->input;
1,240,308,158✔
3432
  SColumnInfoData*      pInputCol = pInput->pData[0];
1,240,308,158✔
3433
  int8_t                inputType = pInputCol->info.type;
1,240,308,158✔
3434
  SColumnInfoData*      pOutput = (SColumnInfoData*)pCtx->pOutput;
1,240,308,158✔
3435
  int32_t               code = TSDB_CODE_SUCCESS;
1,240,308,158✔
3436
  if (pRow->isDataNull) {
1,240,308,158✔
3437
    colDataSetNull_f_s(pOutput, pos);
87,635✔
3438
    pOutput->hasNull = true;
87,635✔
3439

3440
    // handle selectivity
3441
    if (pCtx->subsidiaries.num > 0) {
87,635✔
3442
      code = appendSelectivityCols(pCtx, pRow->block, pRow->rowIndex, pos);
676✔
3443
      if (code != TSDB_CODE_SUCCESS) {
676!
3444
        return code;
×
3445
      }
3446
    }
3447
    return TSDB_CODE_SUCCESS;
87,635✔
3448
  }
3449

3450
  char* pv = pRow->pData;
1,240,220,523✔
3451

3452
  if (pRow->ts == pDiffInfo->prevTs) {
1,240,220,523✔
3453
    return TSDB_CODE_FUNC_DUP_TIMESTAMP;
21✔
3454
  }
3455
  code = doHandleDiff(pDiffInfo, inputType, pv, pOutput, pos, pRow->ts);
1,240,220,502✔
3456
  if (code != TSDB_CODE_SUCCESS) {
1,240,220,502!
3457
    return code;
×
3458
  }
3459
  // handle selectivity
3460
  if (pCtx->subsidiaries.num > 0) {
1,240,220,502✔
3461
    code = appendSelectivityCols(pCtx, pRow->block, pRow->rowIndex, pos);
23,502,613✔
3462
    if (code != TSDB_CODE_SUCCESS) {
23,502,613!
3463
      return code;
×
3464
    }
3465
  }
3466

3467
  return TSDB_CODE_SUCCESS;
1,240,220,502✔
3468
}
3469

3470
int32_t diffFunction(SqlFunctionCtx* pCtx) { return TSDB_CODE_SUCCESS; }
1,519,504✔
3471

3472
int32_t diffFunctionByRow(SArray* pCtxArray) {
1,519,348✔
3473
  int32_t code = TSDB_CODE_SUCCESS;
1,519,348✔
3474
  int     diffColNum = pCtxArray->size;
1,519,348✔
3475
  if (diffColNum == 0) {
1,519,348!
3476
    return TSDB_CODE_SUCCESS;
×
3477
  }
3478
  int32_t numOfElems = 0;
1,519,348✔
3479

3480
  SArray* pRows = taosArrayInit_s(sizeof(SFuncInputRow), diffColNum);
1,519,348✔
3481
  if (NULL == pRows) {
1,519,348!
3482
    return terrno;
×
3483
  }
3484

3485
  bool keepNull = false;
1,519,348✔
3486
  for (int i = 0; i < diffColNum; ++i) {
3,038,852✔
3487
    SqlFunctionCtx* pCtx = *(SqlFunctionCtx**)taosArrayGet(pCtxArray, i);
1,519,504✔
3488
    if (NULL == pCtx) {
1,519,504!
3489
      code = terrno;
×
3490
      goto _exit;
×
3491
    }
3492
    funcInputUpdate(pCtx);
1,519,504✔
3493
    SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
1,519,504✔
3494
    SDiffInfo*           pDiffInfo = GET_ROWCELL_INTERBUF(pResInfo);
1,519,504✔
3495
    if (!ignoreNull(pDiffInfo->ignoreOption)) {
1,519,504✔
3496
      keepNull = true;
1,505,577✔
3497
    }
3498
  }
3499

3500
  SqlFunctionCtx* pCtx0 = *(SqlFunctionCtx**)taosArrayGet(pCtxArray, 0);
1,519,348✔
3501
  SFuncInputRow*  pRow0 = (SFuncInputRow*)taosArrayGet(pRows, 0);
1,519,348✔
3502
  if (NULL == pCtx0 || NULL == pRow0) {
1,519,348!
3503
    code = terrno;
×
3504
    goto _exit;
×
3505
  }
3506
  int32_t startOffset = pCtx0->offset;
1,519,348✔
3507
  bool    result = false;
1,519,348✔
3508
  while (1) {
1,241,035,485✔
3509
    code = funcInputGetNextRow(pCtx0, pRow0, &result);
1,242,554,833✔
3510
    if (TSDB_CODE_SUCCESS != code) {
1,242,554,833!
3511
      goto _exit;
×
3512
    }
3513
    if (!result) {
1,242,554,833✔
3514
      break;
1,519,327✔
3515
    }
3516
    bool hasNotNullValue = !diffResultIsNull(pCtx0, pRow0);
1,241,035,506✔
3517
    for (int i = 1; i < diffColNum; ++i) {
1,241,050,000✔
3518
      SqlFunctionCtx* pCtx = *(SqlFunctionCtx**)taosArrayGet(pCtxArray, i);
14,494✔
3519
      SFuncInputRow*  pRow = (SFuncInputRow*)taosArrayGet(pRows, i);
14,494✔
3520
      if (NULL == pCtx || NULL == pRow) {
14,494!
3521
        code = terrno;
×
3522
        goto _exit;
×
3523
      }
3524
      code = funcInputGetNextRow(pCtx, pRow, &result);
14,494✔
3525
      if (TSDB_CODE_SUCCESS != code) {
14,494!
3526
        goto _exit;
×
3527
      }
3528
      if (!result) {
14,494!
3529
        // rows are not equal
3530
        code = TSDB_CODE_QRY_EXECUTOR_INTERNAL_ERROR;
×
3531
        goto _exit;
×
3532
      }
3533
      if (!diffResultIsNull(pCtx, pRow)) {
14,494✔
3534
        hasNotNullValue = true;
14,052✔
3535
      }
3536
    }
3537
    int32_t pos = startOffset + numOfElems;
1,241,035,506✔
3538

3539
    bool newRow = false;
1,241,035,506✔
3540
    for (int i = 0; i < diffColNum; ++i) {
2,147,483,647✔
3541
      SqlFunctionCtx* pCtx = *(SqlFunctionCtx**)taosArrayGet(pCtxArray, i);
1,241,050,000✔
3542
      SFuncInputRow*  pRow = (SFuncInputRow*)taosArrayGet(pRows, i);
1,241,050,000✔
3543
      if (NULL == pCtx || NULL == pRow) {
1,241,050,000!
3544
        code = terrno;
×
3545
        goto _exit;
×
3546
      }
3547
      if ((keepNull || hasNotNullValue) && !isFirstRow(pCtx, pRow)) {
1,241,050,000✔
3548
        code = setDoDiffResult(pCtx, pRow, pos);
1,240,308,158✔
3549
        if (code != TSDB_CODE_SUCCESS) {
1,240,308,158✔
3550
          goto _exit;
21✔
3551
        }
3552
        newRow = true;
1,240,308,137✔
3553
      } else {
3554
        code = trySetPreVal(pCtx, pRow);
741,842✔
3555
        if (code != TSDB_CODE_SUCCESS) {
741,842!
3556
          goto _exit;
×
3557
        }
3558
      }
3559
    }
3560
    if (newRow) ++numOfElems;
1,241,035,485✔
3561
  }
3562

3563
  for (int i = 0; i < diffColNum; ++i) {
3,038,807✔
3564
    SqlFunctionCtx* pCtx = *(SqlFunctionCtx**)taosArrayGet(pCtxArray, i);
1,519,480✔
3565
    if (NULL == pCtx) {
1,519,480!
3566
      code = terrno;
×
3567
      goto _exit;
×
3568
    }
3569
    SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
1,519,480✔
3570
    pResInfo->numOfRes = numOfElems;
1,519,480✔
3571
  }
3572

3573
_exit:
1,519,327✔
3574
  if (pRows) {
1,519,348!
3575
    taosArrayDestroy(pRows);
1,519,348✔
3576
    pRows = NULL;
1,519,348✔
3577
  }
3578
  return code;
1,519,348✔
3579
}
3580

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

3583
bool getTopBotFuncEnv(SFunctionNode* pFunc, SFuncExecEnv* pEnv) {
81,805✔
3584
  SValueNode* pkNode = (SValueNode*)nodesListGetNode(pFunc->pParameterList, 1);
81,805✔
3585
  pEnv->calcMemSize = sizeof(STopBotRes) + pkNode->datum.i * sizeof(STopBotResItem);
81,865✔
3586
  return true;
81,865✔
3587
}
3588

3589
int32_t topBotFunctionSetup(SqlFunctionCtx* pCtx, SResultRowEntryInfo* pResInfo) {
39,571,957✔
3590
  if (pResInfo->initialized) {
39,571,957!
3591
    return TSDB_CODE_SUCCESS;
×
3592
  }
3593
  if (TSDB_CODE_SUCCESS != functionSetup(pCtx, pResInfo)) {
39,571,957!
3594
    return TSDB_CODE_FUNC_SETUP_ERROR;
×
3595
  }
3596

3597
  STopBotRes*           pRes = GET_ROWCELL_INTERBUF(pResInfo);
39,586,976✔
3598
  SInputColumnInfoData* pInput = &pCtx->input;
39,586,976✔
3599

3600
  pRes->maxSize = pCtx->param[1].param.i;
39,586,976✔
3601

3602
  pRes->nullTupleSaved = false;
39,586,976✔
3603
  pRes->nullTuplePos.pageId = -1;
39,586,976✔
3604
  return TSDB_CODE_SUCCESS;
39,586,976✔
3605
}
3606

3607
static STopBotRes* getTopBotOutputInfo(SqlFunctionCtx* pCtx) {
177,474,887✔
3608
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
177,474,887✔
3609
  STopBotRes*          pRes = GET_ROWCELL_INTERBUF(pResInfo);
177,474,887✔
3610
  pRes->pItems = (STopBotResItem*)((char*)pRes + sizeof(STopBotRes));
177,474,887✔
3611

3612
  return pRes;
177,474,887✔
3613
}
3614

3615
static int32_t doAddIntoResult(SqlFunctionCtx* pCtx, void* pData, int32_t rowIndex, SSDataBlock* pSrcBlock,
3616
                               uint16_t type, uint64_t uid, SResultRowEntryInfo* pEntryInfo, bool isTopQuery);
3617

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

3620
int32_t topFunction(SqlFunctionCtx* pCtx) {
25,971,875✔
3621
  int32_t              numOfElems = 0;
25,971,875✔
3622
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
25,971,875✔
3623

3624
  SInputColumnInfoData* pInput = &pCtx->input;
25,971,875✔
3625
  SColumnInfoData*      pCol = pInput->pData[0];
25,971,875✔
3626

3627
  STopBotRes* pRes = getTopBotOutputInfo(pCtx);
25,971,875✔
3628
  pRes->type = pInput->pData[0]->info.type;
25,970,949✔
3629

3630
  int32_t start = pInput->startRowIndex;
25,970,949✔
3631
  for (int32_t i = start; i < pInput->numOfRows + start; ++i) {
98,102,751✔
3632
    if (pCol->hasNull && colDataIsNull_f(pCol->nullbitmap, i)) {
72,114,380✔
3633
      continue;
21,052✔
3634
    }
3635

3636
    numOfElems++;
72,093,328✔
3637
    char*   data = colDataGetData(pCol, i);
72,093,328!
3638
    int32_t code = doAddIntoResult(pCtx, data, i, pCtx->pSrcBlock, pRes->type, pInput->uid, pResInfo, true);
72,093,328✔
3639
    if (code != TSDB_CODE_SUCCESS) {
72,110,750!
3640
      return code;
×
3641
    }
3642
  }
3643

3644
  if (numOfElems == 0 && pCtx->subsidiaries.num > 0 && !pRes->nullTupleSaved) {
25,988,371✔
3645
    int32_t code = saveTupleData(pCtx, pInput->startRowIndex, pCtx->pSrcBlock, &pRes->nullTuplePos);
89✔
3646
    if (code != TSDB_CODE_SUCCESS) {
89!
3647
      return code;
×
3648
    }
3649
    pRes->nullTupleSaved = true;
89✔
3650
  }
3651
  return TSDB_CODE_SUCCESS;
25,988,371✔
3652
}
3653

3654
int32_t bottomFunction(SqlFunctionCtx* pCtx) {
14,153,039✔
3655
  int32_t              numOfElems = 0;
14,153,039✔
3656
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
14,153,039✔
3657

3658
  SInputColumnInfoData* pInput = &pCtx->input;
14,153,039✔
3659
  SColumnInfoData*      pCol = pInput->pData[0];
14,153,039✔
3660

3661
  STopBotRes* pRes = getTopBotOutputInfo(pCtx);
14,153,039✔
3662
  pRes->type = pInput->pData[0]->info.type;
14,153,040✔
3663

3664
  int32_t start = pInput->startRowIndex;
14,153,040✔
3665
  for (int32_t i = start; i < pInput->numOfRows + start; ++i) {
40,255,124✔
3666
    if (pCol->hasNull && colDataIsNull_f(pCol->nullbitmap, i)) {
26,102,093✔
3667
      continue;
28,018✔
3668
    }
3669

3670
    numOfElems++;
26,074,075✔
3671
    char*   data = colDataGetData(pCol, i);
26,074,075!
3672
    int32_t code = doAddIntoResult(pCtx, data, i, pCtx->pSrcBlock, pRes->type, pInput->uid, pResInfo, false);
26,074,075✔
3673
    if (code != TSDB_CODE_SUCCESS) {
26,074,066!
3674
      return code;
×
3675
    }
3676
  }
3677

3678
  if (numOfElems == 0 && pCtx->subsidiaries.num > 0 && !pRes->nullTupleSaved) {
14,153,031✔
3679
    int32_t code = saveTupleData(pCtx, pInput->startRowIndex, pCtx->pSrcBlock, &pRes->nullTuplePos);
120✔
3680
    if (code != TSDB_CODE_SUCCESS) {
120!
3681
      return code;
×
3682
    }
3683
    pRes->nullTupleSaved = true;
120✔
3684
  }
3685

3686
  return TSDB_CODE_SUCCESS;
14,153,031✔
3687
}
3688

3689
static int32_t topBotResComparFn(const void* p1, const void* p2, const void* param) {
515,611,793✔
3690
  uint16_t type = *(uint16_t*)param;
515,611,793✔
3691

3692
  STopBotResItem* val1 = (STopBotResItem*)p1;
515,611,793✔
3693
  STopBotResItem* val2 = (STopBotResItem*)p2;
515,611,793✔
3694

3695
  if (IS_SIGNED_NUMERIC_TYPE(type)) {
515,611,793!
3696
    if (val1->v.i == val2->v.i) {
288,031,143✔
3697
      return 0;
190,636✔
3698
    }
3699

3700
    return (val1->v.i > val2->v.i) ? 1 : -1;
287,840,507✔
3701
  } else if (IS_UNSIGNED_NUMERIC_TYPE(type)) {
227,580,650!
3702
    if (val1->v.u == val2->v.u) {
477,257✔
3703
      return 0;
101,886✔
3704
    }
3705

3706
    return (val1->v.u > val2->v.u) ? 1 : -1;
375,371✔
3707
  } else if (TSDB_DATA_TYPE_FLOAT == type) {
227,103,393✔
3708
    if (val1->v.f == val2->v.f) {
14,091,231✔
3709
      return 0;
63✔
3710
    }
3711

3712
    return (val1->v.f > val2->v.f) ? 1 : -1;
14,091,168✔
3713
  }
3714

3715
  if (val1->v.d == val2->v.d) {
213,012,162✔
3716
    return 0;
11✔
3717
  }
3718

3719
  return (val1->v.d > val2->v.d) ? 1 : -1;
213,012,151✔
3720
}
3721

3722
int32_t doAddIntoResult(SqlFunctionCtx* pCtx, void* pData, int32_t rowIndex, SSDataBlock* pSrcBlock, uint16_t type,
98,158,500✔
3723
                        uint64_t uid, SResultRowEntryInfo* pEntryInfo, bool isTopQuery) {
3724
  STopBotRes* pRes = getTopBotOutputInfo(pCtx);
98,158,500✔
3725
  int32_t     code = TSDB_CODE_SUCCESS;
98,146,883✔
3726

3727
  SVariant val = {0};
98,146,883✔
3728
  TAOS_CHECK_RETURN(taosVariantCreateFromBinary(&val, pData, tDataTypes[type].bytes, type));
98,146,883!
3729

3730
  STopBotResItem* pItems = pRes->pItems;
98,194,166✔
3731

3732
  // not full yet
3733
  if (pEntryInfo->numOfRes < pRes->maxSize) {
98,194,166✔
3734
    STopBotResItem* pItem = &pItems[pEntryInfo->numOfRes];
66,231,952✔
3735
    pItem->v = val;
66,231,952✔
3736
    pItem->uid = uid;
66,231,952✔
3737

3738
    // save the data of this tuple
3739
    if (pCtx->subsidiaries.num > 0) {
66,231,952✔
3740
      code = saveTupleData(pCtx, rowIndex, pSrcBlock, &pItem->tuplePos);
29,728,752✔
3741
      if (code != TSDB_CODE_SUCCESS) {
29,726,223!
3742
        return code;
×
3743
      }
3744
    }
3745
#ifdef BUF_PAGE_DEBUG
3746
    qDebug("page_saveTuple i:%d, item:%p,pageId:%d, offset:%d\n", pEntryInfo->numOfRes, pItem, pItem->tuplePos.pageId,
3747
           pItem->tuplePos.offset);
3748
#endif
3749
    // allocate the buffer and keep the data of this row into the new allocated buffer
3750
    pEntryInfo->numOfRes++;
66,229,423✔
3751
    code = taosheapsort((void*)pItems, sizeof(STopBotResItem), pEntryInfo->numOfRes, (const void*)&type,
66,229,423✔
3752
                        topBotResComparFn, !isTopQuery);
66,229,423✔
3753
    if (code != TSDB_CODE_SUCCESS) {
66,256,654!
3754
      return code;
×
3755
    }
3756
  } else {  // replace the minimum value in the result
3757
    if ((isTopQuery && ((IS_SIGNED_NUMERIC_TYPE(type) && val.i > pItems[0].v.i) ||
31,962,214✔
3758
                        (IS_UNSIGNED_NUMERIC_TYPE(type) && val.u > pItems[0].v.u) ||
22,653,990!
3759
                        (TSDB_DATA_TYPE_FLOAT == type && val.f > pItems[0].v.f) ||
22,599,479✔
3760
                        (TSDB_DATA_TYPE_DOUBLE == type && val.d > pItems[0].v.d))) ||
22,198,878✔
3761
        (!isTopQuery && ((IS_SIGNED_NUMERIC_TYPE(type) && val.i < pItems[0].v.i) ||
24,640,061!
3762
                         (IS_UNSIGNED_NUMERIC_TYPE(type) && val.u < pItems[0].v.u) ||
4,336,166!
3763
                         (TSDB_DATA_TYPE_FLOAT == type && val.f < pItems[0].v.f) ||
4,335,129✔
3764
                         (TSDB_DATA_TYPE_DOUBLE == type && val.d < pItems[0].v.d)))) {
4,333,846!
3765
      // replace the old data and the coresponding tuple data
3766
      STopBotResItem* pItem = &pItems[0];
9,151,636✔
3767
      pItem->v = val;
9,151,636✔
3768
      pItem->uid = uid;
9,151,636✔
3769

3770
      // save the data of this tuple by over writing the old data
3771
      if (pCtx->subsidiaries.num > 0) {
9,151,636✔
3772
        code = updateTupleData(pCtx, rowIndex, pSrcBlock, &pItem->tuplePos);
5,285,431✔
3773
        if (code != TSDB_CODE_SUCCESS) {
5,284,355!
3774
          return code;
×
3775
        }
3776
      }
3777
#ifdef BUF_PAGE_DEBUG
3778
      qDebug("page_copyTuple pageId:%d, offset:%d", pItem->tuplePos.pageId, pItem->tuplePos.offset);
3779
#endif
3780
      code = taosheapadjust((void*)pItems, sizeof(STopBotResItem), 0, pEntryInfo->numOfRes - 1, (const void*)&type,
9,150,560✔
3781
                            topBotResComparFn, NULL, !isTopQuery);
9,150,560✔
3782
      if (code != TSDB_CODE_SUCCESS) {
9,109,775!
3783
        return code;
×
3784
      }
3785
    }
3786
  }
3787

3788
  return TSDB_CODE_SUCCESS;
98,177,007✔
3789
}
3790

3791
/*
3792
 * +------------------------------------+--------------+--------------+
3793
 * |            null bitmap             |              |              |
3794
 * |(n columns, one bit for each column)| src column #1| src column #2|
3795
 * +------------------------------------+--------------+--------------+
3796
 */
3797
int32_t serializeTupleData(const SSDataBlock* pSrcBlock, int32_t rowIndex, SSubsidiaryResInfo* pSubsidiaryies,
238,716,652✔
3798
                           char* buf, char** res) {
3799
  char* nullList = buf;
238,716,652✔
3800
  char* pStart = (char*)(nullList + sizeof(bool) * pSubsidiaryies->num);
238,716,652✔
3801

3802
  int32_t offset = 0;
238,716,652✔
3803
  for (int32_t i = 0; i < pSubsidiaryies->num; ++i) {
477,260,669✔
3804
    SqlFunctionCtx* pc = pSubsidiaryies->pCtx[i];
238,766,761✔
3805

3806
    // group_key function has its own process function
3807
    // do not process there
3808
    if (fmIsGroupKeyFunc(pc->functionId)) {
238,766,761✔
3809
      continue;
8,396,271✔
3810
    }
3811

3812
    SFunctParam* pFuncParam = &pc->pExpr->base.pParam[0];
230,344,866✔
3813
    int32_t      srcSlotId = pFuncParam->pCol->slotId;
230,344,866✔
3814

3815
    SColumnInfoData* pCol = taosArrayGet(pSrcBlock->pDataBlock, srcSlotId);
230,344,866✔
3816
    if (NULL == pCol) {
230,147,746!
3817
      return TSDB_CODE_OUT_OF_RANGE;
×
3818
    }
3819
    if ((nullList[i] = colDataIsNull_s(pCol, rowIndex)) == true) {
460,295,492✔
3820
      offset += pCol->info.bytes;
293✔
3821
      continue;
293✔
3822
    }
3823

3824
    char* p = colDataGetData(pCol, rowIndex);
230,147,453!
3825
    if (IS_VAR_DATA_TYPE(pCol->info.type)) {
230,147,453!
3826
      (void)memcpy(pStart + offset, p, (pCol->info.type == TSDB_DATA_TYPE_JSON) ? getJsonValueLen(p) : varDataTLen(p));
30,875!
3827
    } else {
3828
      (void)memcpy(pStart + offset, p, pCol->info.bytes);
230,116,578✔
3829
    }
3830

3831
    offset += pCol->info.bytes;
230,147,453✔
3832
  }
3833

3834
  *res = buf;
238,493,908✔
3835
  return TSDB_CODE_SUCCESS;
238,493,908✔
3836
}
3837

3838
static int32_t doSaveTupleData(SSerializeDataHandle* pHandle, const void* pBuf, size_t length, SWinKey* key,
203,293,213✔
3839
                               STuplePos* pPos, SFunctionStateStore* pStore) {
3840
  STuplePos p = {0};
203,293,213✔
3841
  if (pHandle->pBuf != NULL) {
203,293,213✔
3842
    SFilePage* pPage = NULL;
203,258,236✔
3843

3844
    if (pHandle->currentPage == -1) {
203,258,236✔
3845
      pPage = getNewBufPage(pHandle->pBuf, &pHandle->currentPage);
650,691✔
3846
      if (pPage == NULL) {
650,690!
3847
        return terrno;
×
3848
      }
3849
      pPage->num = sizeof(SFilePage);
650,690✔
3850
    } else {
3851
      pPage = getBufPage(pHandle->pBuf, pHandle->currentPage);
202,607,545✔
3852
      if (pPage == NULL) {
202,589,587!
3853
        return terrno;
×
3854
      }
3855
      if (pPage->num + length > getBufPageSize(pHandle->pBuf)) {
202,589,587✔
3856
        // current page is all used, let's prepare a new buffer page
3857
        releaseBufPage(pHandle->pBuf, pPage);
367,003✔
3858
        pPage = getNewBufPage(pHandle->pBuf, &pHandle->currentPage);
367,003✔
3859
        if (pPage == NULL) {
367,003!
3860
          return terrno;
×
3861
        }
3862
        pPage->num = sizeof(SFilePage);
367,003✔
3863
      }
3864
    }
3865

3866
    p = (STuplePos){.pageId = pHandle->currentPage, .offset = pPage->num};
203,228,075✔
3867
    (void)memcpy(pPage->data + pPage->num, pBuf, length);
203,228,075✔
3868

3869
    pPage->num += length;
203,228,075✔
3870
    setBufPageDirty(pPage, true);
203,228,075✔
3871
    releaseBufPage(pHandle->pBuf, pPage);
203,154,204✔
3872
  } else {  // other tuple save policy
3873
    if (pStore->streamStateFuncPut(pHandle->pState, key, pBuf, length) >= 0) {
34,977!
3874
      p.streamTupleKey = *key;
44,272✔
3875
    }
3876
  }
3877

3878
  *pPos = p;
203,133,625✔
3879
  return TSDB_CODE_SUCCESS;
203,133,625✔
3880
}
3881

3882
int32_t saveTupleData(SqlFunctionCtx* pCtx, int32_t rowIndex, const SSDataBlock* pSrcBlock, STuplePos* pPos) {
154,189,142✔
3883
  int32_t code = prepareBuf(pCtx);
154,189,142✔
3884
  if (TSDB_CODE_SUCCESS != code) {
154,167,522!
3885
    return code;
×
3886
  }
3887

3888
  SWinKey key = {0};
154,167,522✔
3889
  if (pCtx->saveHandle.pBuf == NULL) {
154,167,522✔
3890
    SColumnInfoData* pColInfo = taosArrayGet(pSrcBlock->pDataBlock, pCtx->saveHandle.pState->tsIndex);
44,271✔
3891
    if (NULL == pColInfo) {
44,272!
3892
      return TSDB_CODE_OUT_OF_RANGE;
×
3893
    }
3894
    if (pColInfo->info.type != TSDB_DATA_TYPE_TIMESTAMP) {
44,272!
3895
      return TSDB_CODE_FUNC_FUNTION_PARA_TYPE;
×
3896
    }
3897
    key.groupId = pSrcBlock->info.id.groupId;
44,272✔
3898
    key.ts = *(int64_t*)colDataGetData(pColInfo, rowIndex);
44,272!
3899
  }
3900

3901
  char* buf = NULL;
154,167,523✔
3902
  code = serializeTupleData(pSrcBlock, rowIndex, &pCtx->subsidiaries, pCtx->subsidiaries.buf, &buf);
154,167,523✔
3903
  if (TSDB_CODE_SUCCESS != code) {
154,068,057!
3904
    return code;
×
3905
  }
3906
  return doSaveTupleData(&pCtx->saveHandle, buf, pCtx->subsidiaries.rowLen, &key, pPos, pCtx->pStore);
154,068,057✔
3907
}
3908

3909
static int32_t doUpdateTupleData(SSerializeDataHandle* pHandle, const void* pBuf, size_t length, STuplePos* pPos,
84,584,196✔
3910
                                 SFunctionStateStore* pStore) {
3911
  if (pHandle->pBuf != NULL) {
84,584,196✔
3912
    SFilePage* pPage = getBufPage(pHandle->pBuf, pPos->pageId);
84,509,812✔
3913
    if (pPage == NULL) {
84,509,199!
3914
      return terrno;
×
3915
    }
3916
    (void)memcpy(pPage->data + pPos->offset, pBuf, length);
84,509,199✔
3917
    setBufPageDirty(pPage, true);
84,509,199✔
3918
    releaseBufPage(pHandle->pBuf, pPage);
84,506,872✔
3919
  } else {
3920
    int32_t code = pStore->streamStateFuncPut(pHandle->pState, &pPos->streamTupleKey, pBuf, length);
74,384✔
3921
    if (TSDB_CODE_SUCCESS != code) {
74,697!
3922
      return code;
×
3923
    }
3924
  }
3925

3926
  return TSDB_CODE_SUCCESS;
84,578,899✔
3927
}
3928

3929
int32_t updateTupleData(SqlFunctionCtx* pCtx, int32_t rowIndex, const SSDataBlock* pSrcBlock, STuplePos* pPos) {
84,587,947✔
3930
  int32_t code = prepareBuf(pCtx);
84,587,947✔
3931
  if (TSDB_CODE_SUCCESS != code) {
84,587,154!
3932
    return code;
×
3933
  }
3934

3935
  char* buf = NULL;
84,587,154✔
3936
  code = serializeTupleData(pSrcBlock, rowIndex, &pCtx->subsidiaries, pCtx->subsidiaries.buf, &buf);
84,587,154✔
3937
  if (TSDB_CODE_SUCCESS != code) {
84,583,928!
3938
    return code;
×
3939
  }
3940
  return doUpdateTupleData(&pCtx->saveHandle, buf, pCtx->subsidiaries.rowLen, pPos, pCtx->pStore);
84,583,928✔
3941
}
3942

3943
static int32_t doLoadTupleData(SSerializeDataHandle* pHandle, const STuplePos* pPos, SFunctionStateStore* pStore,
128,531,465✔
3944
                               char** value) {
3945
  if (pHandle->pBuf != NULL) {
128,531,465✔
3946
    SFilePage* pPage = getBufPage(pHandle->pBuf, pPos->pageId);
128,491,236✔
3947
    if (pPage == NULL) {
128,652,163!
3948
      *value = NULL;
×
3949
      return terrno;
×
3950
    }
3951
    *value = pPage->data + pPos->offset;
128,652,163✔
3952
    releaseBufPage(pHandle->pBuf, pPage);
128,652,163✔
3953
    return TSDB_CODE_SUCCESS;
128,613,504✔
3954
  } else {
3955
    *value = NULL;
40,229✔
3956
    int32_t vLen;
3957
    int32_t code = pStore->streamStateFuncGet(pHandle->pState, &pPos->streamTupleKey, (void**)(value), &vLen);
40,229✔
3958
    if (TSDB_CODE_SUCCESS != code) {
43,821!
3959
      return code;
×
3960
    }
3961
    return TSDB_CODE_SUCCESS;
43,821✔
3962
  }
3963
}
3964

3965
int32_t loadTupleData(SqlFunctionCtx* pCtx, const STuplePos* pPos, char** value) {
128,391,728✔
3966
  return doLoadTupleData(&pCtx->saveHandle, pPos, pCtx->pStore, value);
128,391,728✔
3967
}
3968

3969
int32_t topBotFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
39,356,902✔
3970
  int32_t code = TSDB_CODE_SUCCESS;
39,356,902✔
3971

3972
  SResultRowEntryInfo* pEntryInfo = GET_RES_INFO(pCtx);
39,356,902✔
3973
  STopBotRes*          pRes = getTopBotOutputInfo(pCtx);
39,356,902✔
3974

3975
  int16_t type = pCtx->pExpr->base.resSchema.type;
39,354,782✔
3976
  int32_t slotId = pCtx->pExpr->base.resSchema.slotId;
39,354,782✔
3977

3978
  SColumnInfoData* pCol = taosArrayGet(pBlock->pDataBlock, slotId);
39,354,782✔
3979
  if (NULL == pCol) {
39,345,422!
3980
    return TSDB_CODE_OUT_OF_RANGE;
×
3981
  }
3982

3983
  // todo assign the tag value and the corresponding row data
3984
  int32_t currentRow = pBlock->info.rows;
39,345,422✔
3985
  if (pEntryInfo->numOfRes <= 0) {
39,345,422✔
3986
    colDataSetNULL(pCol, currentRow);
475!
3987
    code = setSelectivityValue(pCtx, pBlock, &pRes->nullTuplePos, currentRow);
475✔
3988
    return code;
475✔
3989
  }
3990
  for (int32_t i = 0; i < pEntryInfo->numOfRes; ++i) {
104,985,285✔
3991
    STopBotResItem* pItem = &pRes->pItems[i];
65,665,661✔
3992
    code = colDataSetVal(pCol, currentRow, (const char*)&pItem->v.i, false);
65,665,661✔
3993
    if (TSDB_CODE_SUCCESS != code) {
65,636,193!
3994
      return code;
×
3995
    }
3996
#ifdef BUF_PAGE_DEBUG
3997
    qDebug("page_finalize i:%d,item:%p,pageId:%d, offset:%d\n", i, pItem, pItem->tuplePos.pageId,
3998
           pItem->tuplePos.offset);
3999
#endif
4000
    code = setSelectivityValue(pCtx, pBlock, &pRes->pItems[i].tuplePos, currentRow);
65,636,193✔
4001
    if (TSDB_CODE_SUCCESS != code) {
65,640,338!
4002
      return code;
×
4003
    }
4004
    currentRow += 1;
65,640,338✔
4005
  }
4006

4007
  return code;
39,319,624✔
4008
}
4009

4010
int32_t addResult(SqlFunctionCtx* pCtx, STopBotResItem* pSourceItem, int16_t type, bool isTopQuery) {
×
4011
  SResultRowEntryInfo* pEntryInfo = GET_RES_INFO(pCtx);
×
4012
  STopBotRes*          pRes = getTopBotOutputInfo(pCtx);
×
4013
  STopBotResItem*      pItems = pRes->pItems;
×
4014
  int32_t              code = TSDB_CODE_SUCCESS;
×
4015

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

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

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

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

4083
int32_t getSpreadInfoSize() { return (int32_t)sizeof(SSpreadInfo); }
854,501✔
4084

4085
bool getSpreadFuncEnv(SFunctionNode* UNUSED_PARAM(pFunc), SFuncExecEnv* pEnv) {
103,747✔
4086
  pEnv->calcMemSize = sizeof(SSpreadInfo);
103,747✔
4087
  return true;
103,747✔
4088
}
4089

4090
int32_t spreadFunctionSetup(SqlFunctionCtx* pCtx, SResultRowEntryInfo* pResultInfo) {
4,296,966✔
4091
  if (pResultInfo->initialized) {
4,296,966!
4092
    return TSDB_CODE_SUCCESS;
×
4093
  }
4094
  if (TSDB_CODE_SUCCESS != functionSetup(pCtx, pResultInfo)) {
4,296,966!
4095
    return TSDB_CODE_FUNC_SETUP_ERROR;
×
4096
  }
4097

4098
  SSpreadInfo* pInfo = GET_ROWCELL_INTERBUF(pResultInfo);
4,296,994✔
4099
  SET_DOUBLE_VAL(&pInfo->min, DBL_MAX);
4,296,994✔
4100
  SET_DOUBLE_VAL(&pInfo->max, -DBL_MAX);
4,296,994✔
4101
  pInfo->hasResult = false;
4,296,994✔
4102
  return TSDB_CODE_SUCCESS;
4,296,994✔
4103
}
4104

4105
int32_t spreadFunction(SqlFunctionCtx* pCtx) {
4,270,903✔
4106
  int32_t numOfElems = 0;
4,270,903✔
4107

4108
  // Only the pre-computing information loaded and actual data does not loaded
4109
  SInputColumnInfoData* pInput = &pCtx->input;
4,270,903✔
4110
  SColumnDataAgg*       pAgg = pInput->pColumnDataAgg[0];
4,270,903✔
4111
  int32_t               type = pInput->pData[0]->info.type;
4,270,903✔
4112

4113
  SSpreadInfo* pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
4,270,903✔
4114

4115
  if (pInput->colDataSMAIsSet) {
4,270,903!
4116
    numOfElems = pInput->numOfRows - pAgg->numOfNull;
×
4117
    if (numOfElems == 0) {
×
4118
      goto _spread_over;
×
4119
    }
4120
    double tmin = 0.0, tmax = 0.0;
×
4121
    if (IS_SIGNED_NUMERIC_TYPE(type) || IS_TIMESTAMP_TYPE(type)) {
×
4122
      tmin = (double)GET_INT64_VAL(&pAgg->min);
×
4123
      tmax = (double)GET_INT64_VAL(&pAgg->max);
×
4124
    } else if (IS_FLOAT_TYPE(type)) {
×
4125
      tmin = GET_DOUBLE_VAL(&pAgg->min);
×
4126
      tmax = GET_DOUBLE_VAL(&pAgg->max);
×
4127
    } else if (IS_UNSIGNED_NUMERIC_TYPE(type)) {
×
4128
      tmin = (double)GET_UINT64_VAL(&pAgg->min);
×
4129
      tmax = (double)GET_UINT64_VAL(&pAgg->max);
×
4130
    }
4131

4132
    if (GET_DOUBLE_VAL(&pInfo->min) > tmin) {
×
4133
      SET_DOUBLE_VAL(&pInfo->min, tmin);
×
4134
    }
4135

4136
    if (GET_DOUBLE_VAL(&pInfo->max) < tmax) {
×
4137
      SET_DOUBLE_VAL(&pInfo->max, tmax);
×
4138
    }
4139

4140
  } else {  // computing based on the true data block
4141
    SColumnInfoData* pCol = pInput->pData[0];
4,270,903✔
4142

4143
    int32_t start = pInput->startRowIndex;
4,270,903✔
4144
    // check the valid data one by one
4145
    for (int32_t i = start; i < pInput->numOfRows + start; ++i) {
20,889,408✔
4146
      if (colDataIsNull_f(pCol->nullbitmap, i)) {
16,618,505✔
4147
        continue;
1,588,590✔
4148
      }
4149

4150
      char* data = colDataGetData(pCol, i);
15,029,915!
4151

4152
      double v = 0;
15,029,915✔
4153
      GET_TYPED_DATA(v, double, type, data);
15,029,915!
4154
      if (v < GET_DOUBLE_VAL(&pInfo->min)) {
15,029,915✔
4155
        SET_DOUBLE_VAL(&pInfo->min, v);
5,094,203✔
4156
      }
4157

4158
      if (v > GET_DOUBLE_VAL(&pInfo->max)) {
15,029,915✔
4159
        SET_DOUBLE_VAL(&pInfo->max, v);
5,583,272✔
4160
      }
4161

4162
      numOfElems += 1;
15,029,915✔
4163
    }
4164
  }
4165

4166
_spread_over:
4,270,903✔
4167
  // data in the check operation are all null, not output
4168
  SET_VAL(GET_RES_INFO(pCtx), numOfElems, 1);
4,270,903✔
4169
  if (numOfElems > 0) {
4,270,903✔
4170
    pInfo->hasResult = true;
4,246,297✔
4171
  }
4172

4173
  return TSDB_CODE_SUCCESS;
4,270,903✔
4174
}
4175

4176
static void spreadTransferInfo(SSpreadInfo* pInput, SSpreadInfo* pOutput) {
852,993✔
4177
  pOutput->hasResult = pInput->hasResult;
852,993✔
4178
  if (pInput->max > pOutput->max) {
852,993✔
4179
    pOutput->max = pInput->max;
848,478✔
4180
  }
4181

4182
  if (pInput->min < pOutput->min) {
852,993✔
4183
    pOutput->min = pInput->min;
848,461✔
4184
  }
4185
}
852,993✔
4186

4187
int32_t spreadFunctionMerge(SqlFunctionCtx* pCtx) {
849,038✔
4188
  SInputColumnInfoData* pInput = &pCtx->input;
849,038✔
4189
  SColumnInfoData*      pCol = pInput->pData[0];
849,038✔
4190

4191
  if (IS_NULL_TYPE(pCol->info.type)) {
849,038!
4192
    SET_VAL(GET_RES_INFO(pCtx), 0, 1);
×
4193
    return TSDB_CODE_SUCCESS;
×
4194
  }
4195

4196
  if (pCol->info.type != TSDB_DATA_TYPE_BINARY) {
849,038!
4197
    return TSDB_CODE_FUNC_FUNTION_PARA_TYPE;
×
4198
  }
4199

4200
  SSpreadInfo* pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
849,038✔
4201

4202
  int32_t start = pInput->startRowIndex;
849,038✔
4203
  for (int32_t i = start; i < start + pInput->numOfRows; ++i) {
1,702,249✔
4204
    if (colDataIsNull_s(pCol, i)) continue;
1,706,422!
4205
    char*        data = colDataGetData(pCol, i);
853,211!
4206
    SSpreadInfo* pInputInfo = (SSpreadInfo*)varDataVal(data);
853,211✔
4207
    if (pInputInfo->hasResult) {
853,211✔
4208
      spreadTransferInfo(pInputInfo, pInfo);
852,992✔
4209
    }
4210
  }
4211

4212
  if (pInfo->hasResult) {
849,038✔
4213
    GET_RES_INFO(pCtx)->numOfRes = 1;
848,882✔
4214
  }
4215

4216
  return TSDB_CODE_SUCCESS;
849,038✔
4217
}
4218

4219
int32_t spreadFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
3,434,782✔
4220
  SSpreadInfo* pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
3,434,782✔
4221
  if (pInfo->hasResult == true) {
3,434,782✔
4222
    SET_DOUBLE_VAL(&pInfo->result, pInfo->max - pInfo->min);
3,410,602✔
4223
  } else {
4224
    GET_RES_INFO(pCtx)->isNullRes = 1;
24,180✔
4225
  }
4226
  return functionFinalize(pCtx, pBlock);
3,434,782✔
4227
}
4228

4229
int32_t spreadPartialFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
853,000✔
4230
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
853,000✔
4231
  SSpreadInfo*         pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
853,000✔
4232
  int32_t              resultBytes = getSpreadInfoSize();
853,000✔
4233
  char*                res = taosMemoryCalloc(resultBytes + VARSTR_HEADER_SIZE, sizeof(char));
853,000!
4234

4235
  if (NULL == res) {
853,002!
4236
    return terrno;
×
4237
  }
4238
  (void)memcpy(varDataVal(res), pInfo, resultBytes);
853,002✔
4239
  varDataSetLen(res, resultBytes);
853,002✔
4240

4241
  int32_t          slotId = pCtx->pExpr->base.resSchema.slotId;
853,002✔
4242
  int32_t          code = TSDB_CODE_SUCCESS;
853,002✔
4243
  SColumnInfoData* pCol = taosArrayGet(pBlock->pDataBlock, slotId);
853,002✔
4244
  if (NULL == pCol) {
853,002!
4245
    code = terrno;
×
4246
    goto _exit;
×
4247
  }
4248

4249
  code = colDataSetVal(pCol, pBlock->info.rows, res, false);
853,002✔
4250
  if (TSDB_CODE_SUCCESS != code) {
853,002!
4251
    goto _exit;
×
4252
  }
4253

4254
_exit:
853,002✔
4255
  taosMemoryFree(res);
853,002!
4256
  return code;
853,002✔
4257
}
4258

4259
int32_t spreadCombine(SqlFunctionCtx* pDestCtx, SqlFunctionCtx* pSourceCtx) {
1✔
4260
  SResultRowEntryInfo* pDResInfo = GET_RES_INFO(pDestCtx);
1✔
4261
  SSpreadInfo*         pDBuf = GET_ROWCELL_INTERBUF(pDResInfo);
1✔
4262

4263
  SResultRowEntryInfo* pSResInfo = GET_RES_INFO(pSourceCtx);
1✔
4264
  SSpreadInfo*         pSBuf = GET_ROWCELL_INTERBUF(pSResInfo);
1✔
4265
  spreadTransferInfo(pSBuf, pDBuf);
1✔
4266
  pDResInfo->numOfRes = TMAX(pDResInfo->numOfRes, pSResInfo->numOfRes);
1✔
4267
  pDResInfo->isNullRes &= pSResInfo->isNullRes;
1✔
4268
  return TSDB_CODE_SUCCESS;
1✔
4269
}
4270

4271
int32_t getElapsedInfoSize() { return (int32_t)sizeof(SElapsedInfo); }
×
4272

4273
bool getElapsedFuncEnv(SFunctionNode* UNUSED_PARAM(pFunc), SFuncExecEnv* pEnv) {
103,035✔
4274
  pEnv->calcMemSize = sizeof(SElapsedInfo);
103,035✔
4275
  return true;
103,035✔
4276
}
4277

4278
int32_t elapsedFunctionSetup(SqlFunctionCtx* pCtx, SResultRowEntryInfo* pResultInfo) {
8,848,542✔
4279
  if (pResultInfo->initialized) {
8,848,542!
4280
    return TSDB_CODE_SUCCESS;
×
4281
  }
4282
  if (TSDB_CODE_SUCCESS != functionSetup(pCtx, pResultInfo)) {
8,848,542!
4283
    return TSDB_CODE_FUNC_SETUP_ERROR;
×
4284
  }
4285

4286
  SElapsedInfo* pInfo = GET_ROWCELL_INTERBUF(pResultInfo);
8,848,547✔
4287
  pInfo->result = 0;
8,848,547✔
4288
  pInfo->min = TSKEY_MAX;
8,848,547✔
4289
  pInfo->max = 0;
8,848,547✔
4290

4291
  if (pCtx->numOfParams > 1) {
8,848,547✔
4292
    pInfo->timeUnit = pCtx->param[1].param.i;
22,525✔
4293
  } else {
4294
    pInfo->timeUnit = 1;
8,826,022✔
4295
  }
4296

4297
  return TSDB_CODE_SUCCESS;
8,848,547✔
4298
}
4299

4300
int32_t elapsedFunction(SqlFunctionCtx* pCtx) {
8,848,700✔
4301
  int32_t numOfElems = 0;
8,848,700✔
4302

4303
  // Only the pre-computing information loaded and actual data does not loaded
4304
  SInputColumnInfoData* pInput = &pCtx->input;
8,848,700✔
4305
  SColumnDataAgg*       pAgg = pInput->pColumnDataAgg[0];
8,848,700✔
4306

4307
  SElapsedInfo* pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
8,848,700✔
4308

4309
  numOfElems = pInput->numOfRows;  // since this is the primary timestamp, no need to exclude NULL values
8,848,700✔
4310
  if (numOfElems == 0) {
8,848,700✔
4311
    // for stream
4312
    if (pCtx->end.key != INT64_MIN) {
54!
4313
      pInfo->max = pCtx->end.key + 1;
54✔
4314
    }
4315
    goto _elapsed_over;
54✔
4316
  }
4317

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

4343
    SColumnInfoData* pCol = pInput->pData[0];
8,848,646✔
4344

4345
    int32_t start = pInput->startRowIndex;
8,848,646✔
4346
    TSKEY*  ptsList = (int64_t*)colDataGetData(pCol, 0);
8,848,646!
4347
    if (pCtx->order == TSDB_ORDER_DESC) {
8,848,646✔
4348
      if (pCtx->start.key == INT64_MIN) {
676!
4349
        pInfo->max = (pInfo->max < ptsList[start]) ? ptsList[start] : pInfo->max;
676✔
4350
      } else {
4351
        pInfo->max = pCtx->start.key + 1;
×
4352
      }
4353

4354
      if (pCtx->end.key == INT64_MIN) {
676!
4355
        pInfo->min =
676✔
4356
            (pInfo->min > ptsList[start + pInput->numOfRows - 1]) ? ptsList[start + pInput->numOfRows - 1] : pInfo->min;
676✔
4357
      } else {
4358
        pInfo->min = pCtx->end.key;
×
4359
      }
4360
    } else {
4361
      if (pCtx->start.key == INT64_MIN) {
8,847,970✔
4362
        pInfo->min = (pInfo->min > ptsList[start]) ? ptsList[start] : pInfo->min;
4,078,298✔
4363
      } else {
4364
        pInfo->min = pCtx->start.key;
4,769,672✔
4365
      }
4366

4367
      if (pCtx->end.key == INT64_MIN) {
8,847,970✔
4368
        pInfo->max =
3,873,187✔
4369
            (pInfo->max < ptsList[start + pInput->numOfRows - 1]) ? ptsList[start + pInput->numOfRows - 1] : pInfo->max;
3,873,187✔
4370
      } else {
4371
        pInfo->max = pCtx->end.key + 1;
4,974,783✔
4372
      }
4373
    }
4374
  }
4375

4376
_elapsed_over:
8,848,700✔
4377
  // data in the check operation are all null, not output
4378
  SET_VAL(GET_RES_INFO(pCtx), numOfElems, 1);
8,848,700✔
4379

4380
  return TSDB_CODE_SUCCESS;
8,848,700✔
4381
}
4382

4383
static void elapsedTransferInfo(SElapsedInfo* pInput, SElapsedInfo* pOutput) {
×
4384
  pOutput->timeUnit = pInput->timeUnit;
×
4385
  if (pOutput->min > pInput->min) {
×
4386
    pOutput->min = pInput->min;
×
4387
  }
4388

4389
  if (pOutput->max < pInput->max) {
×
4390
    pOutput->max = pInput->max;
×
4391
  }
4392
}
×
4393

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

4401
  SElapsedInfo* pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
×
4402

4403
  int32_t start = pInput->startRowIndex;
×
4404

4405
  for (int32_t i = start; i < start + pInput->numOfRows; ++i) {
×
4406
    char*         data = colDataGetData(pCol, i);
×
4407
    SElapsedInfo* pInputInfo = (SElapsedInfo*)varDataVal(data);
×
4408
    elapsedTransferInfo(pInputInfo, pInfo);
×
4409
  }
4410

4411
  SET_VAL(GET_RES_INFO(pCtx), 1, 1);
×
4412
  return TSDB_CODE_SUCCESS;
×
4413
}
4414

4415
int32_t elapsedFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
8,826,524✔
4416
  SElapsedInfo* pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
8,826,524✔
4417
  double        result = (double)pInfo->max - (double)pInfo->min;
8,826,524✔
4418
  result = (result >= 0) ? result : -result;
8,826,524✔
4419
  pInfo->result = result / pInfo->timeUnit;
8,826,524✔
4420
  return functionFinalize(pCtx, pBlock);
8,826,524✔
4421
}
4422

4423
int32_t elapsedPartialFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
×
4424
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
×
4425
  SElapsedInfo*        pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
×
4426
  int32_t              resultBytes = getElapsedInfoSize();
×
4427
  char*                res = taosMemoryCalloc(resultBytes + VARSTR_HEADER_SIZE, sizeof(char));
×
4428

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

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

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

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

4456
  SResultRowEntryInfo* pSResInfo = GET_RES_INFO(pSourceCtx);
×
4457
  SElapsedInfo*        pSBuf = GET_ROWCELL_INTERBUF(pSResInfo);
×
4458

4459
  elapsedTransferInfo(pSBuf, pDBuf);
×
4460
  pDResInfo->numOfRes = TMAX(pDResInfo->numOfRes, pSResInfo->numOfRes);
×
4461
  pDResInfo->isNullRes &= pSResInfo->isNullRes;
×
4462
  return TSDB_CODE_SUCCESS;
×
4463
}
4464

4465
int32_t getHistogramInfoSize() {
2,971,016✔
4466
  return (int32_t)sizeof(SHistoFuncInfo) + HISTOGRAM_MAX_BINS_NUM * sizeof(SHistoFuncBin);
2,971,016✔
4467
}
4468

4469
bool getHistogramFuncEnv(SFunctionNode* UNUSED_PARAM(pFunc), SFuncExecEnv* pEnv) {
111,968✔
4470
  pEnv->calcMemSize = sizeof(SHistoFuncInfo) + HISTOGRAM_MAX_BINS_NUM * sizeof(SHistoFuncBin);
111,968✔
4471
  return true;
111,968✔
4472
}
4473

4474
static int8_t getHistogramBinType(char* binTypeStr) {
15,008,450✔
4475
  int8_t binType;
4476
  if (strcasecmp(binTypeStr, "user_input") == 0) {
15,008,450✔
4477
    binType = USER_INPUT_BIN;
3,848✔
4478
  } else if (strcasecmp(binTypeStr, "linear_bin") == 0) {
15,004,602✔
4479
    binType = LINEAR_BIN;
1,880✔
4480
  } else if (strcasecmp(binTypeStr, "log_bin") == 0) {
15,002,722!
4481
    binType = LOG_BIN;
15,003,049✔
4482
  } else {
4483
    binType = UNKNOWN_BIN;
×
4484
  }
4485

4486
  return binType;
15,008,450✔
4487
}
4488

4489
static int32_t getHistogramBinDesc(SHistoFuncInfo* pInfo, char* binDescStr, int8_t binType, bool normalized) {
15,008,719✔
4490
  cJSON*  binDesc = cJSON_Parse(binDescStr);
15,008,719✔
4491
  int32_t numOfBins;
4492
  double* intervals;
4493
  if (cJSON_IsObject(binDesc)) { /* linaer/log bins */
15,008,734✔
4494
    int32_t numOfParams = cJSON_GetArraySize(binDesc);
15,004,823✔
4495
    int32_t startIndex;
4496
    if (numOfParams != 4) {
15,004,749!
4497
      cJSON_Delete(binDesc);
×
4498
      return TSDB_CODE_FAILED;
×
4499
    }
4500

4501
    cJSON* start = cJSON_GetObjectItem(binDesc, "start");
15,004,749✔
4502
    cJSON* factor = cJSON_GetObjectItem(binDesc, "factor");
15,005,017✔
4503
    cJSON* width = cJSON_GetObjectItem(binDesc, "width");
15,004,768✔
4504
    cJSON* count = cJSON_GetObjectItem(binDesc, "count");
15,003,028✔
4505
    cJSON* infinity = cJSON_GetObjectItem(binDesc, "infinity");
15,004,280✔
4506

4507
    if (!cJSON_IsNumber(start) || !cJSON_IsNumber(count) || !cJSON_IsBool(infinity)) {
15,004,909!
4508
      cJSON_Delete(binDesc);
×
4509
      return TSDB_CODE_FAILED;
×
4510
    }
4511

4512
    if (count->valueint <= 0 || count->valueint > 1000) {  // limit count to 1000
15,004,743!
4513
      cJSON_Delete(binDesc);
×
4514
      return TSDB_CODE_FAILED;
×
4515
    }
4516

4517
    if (isinf(start->valuedouble) || (width != NULL && isinf(width->valuedouble)) ||
15,004,777!
4518
        (factor != NULL && isinf(factor->valuedouble)) || (count != NULL && isinf(count->valuedouble))) {
15,004,777!
4519
      cJSON_Delete(binDesc);
×
4520
      return TSDB_CODE_FAILED;
×
4521
    }
4522

4523
    int32_t counter = (int32_t)count->valueint;
15,004,777✔
4524
    if (infinity->valueint == false) {
15,004,777✔
4525
      startIndex = 0;
11,147,030✔
4526
      numOfBins = counter + 1;
11,147,030✔
4527
    } else {
4528
      startIndex = 1;
3,857,747✔
4529
      numOfBins = counter + 3;
3,857,747✔
4530
    }
4531

4532
    intervals = taosMemoryCalloc(numOfBins, sizeof(double));
15,004,777!
4533
    if (NULL == intervals) {
15,004,814!
4534
      cJSON_Delete(binDesc);
×
4535
      qError("histogram function out of memory");
×
4536
      return terrno;
×
4537
    }
4538
    if (cJSON_IsNumber(width) && factor == NULL && binType == LINEAR_BIN) {
15,004,814!
4539
      // linear bin process
4540
      if (width->valuedouble == 0) {
1,880!
4541
        taosMemoryFree(intervals);
×
4542
        cJSON_Delete(binDesc);
×
4543
        return TSDB_CODE_FAILED;
×
4544
      }
4545
      for (int i = 0; i < counter + 1; ++i) {
10,856✔
4546
        intervals[startIndex] = start->valuedouble + i * width->valuedouble;
8,976✔
4547
        if (isinf(intervals[startIndex])) {
8,976!
4548
          taosMemoryFree(intervals);
×
4549
          cJSON_Delete(binDesc);
×
4550
          return TSDB_CODE_FAILED;
×
4551
        }
4552
        startIndex++;
8,976✔
4553
      }
4554
    } else if (cJSON_IsNumber(factor) && width == NULL && binType == LOG_BIN) {
15,002,924!
4555
      // log bin process
4556
      if (start->valuedouble == 0) {
15,002,963!
4557
        taosMemoryFree(intervals);
×
4558
        cJSON_Delete(binDesc);
×
4559
        return TSDB_CODE_FAILED;
×
4560
      }
4561
      if (factor->valuedouble < 0 || factor->valuedouble == 0 || factor->valuedouble == 1) {
15,002,963!
4562
        taosMemoryFree(intervals);
×
4563
        cJSON_Delete(binDesc);
×
4564
        return TSDB_CODE_FAILED;
×
4565
      }
4566
      for (int i = 0; i < counter + 1; ++i) {
105,008,929✔
4567
        intervals[startIndex] = start->valuedouble * pow(factor->valuedouble, i * 1.0);
90,005,889✔
4568
        if (isinf(intervals[startIndex])) {
90,005,889!
4569
          taosMemoryFree(intervals);
×
4570
          cJSON_Delete(binDesc);
×
4571
          return TSDB_CODE_FAILED;
×
4572
        }
4573
        startIndex++;
90,005,889✔
4574
      }
4575
    } else {
4576
      taosMemoryFree(intervals);
×
4577
      cJSON_Delete(binDesc);
×
4578
      return TSDB_CODE_FAILED;
×
4579
    }
4580

4581
    if (infinity->valueint == true) {
15,004,920✔
4582
      intervals[0] = -INFINITY;
3,858,456✔
4583
      intervals[numOfBins - 1] = INFINITY;
3,858,456✔
4584
      // in case of desc bin orders, -inf/inf should be swapped
4585
      if (numOfBins < 4) {
3,858,456!
4586
        return TSDB_CODE_FAILED;
×
4587
      }
4588
      if (intervals[1] > intervals[numOfBins - 2]) {
3,858,456✔
4589
        TSWAP(intervals[0], intervals[numOfBins - 1]);
3,857,491✔
4590
      }
4591
    }
4592
  } else if (cJSON_IsArray(binDesc)) { /* user input bins */
3,848!
4593
    if (binType != USER_INPUT_BIN) {
3,848!
4594
      cJSON_Delete(binDesc);
×
4595
      return TSDB_CODE_FAILED;
×
4596
    }
4597
    numOfBins = cJSON_GetArraySize(binDesc);
3,848✔
4598
    intervals = taosMemoryCalloc(numOfBins, sizeof(double));
3,849!
4599
    if (NULL == intervals) {
3,848!
4600
      cJSON_Delete(binDesc);
×
4601
      qError("histogram function out of memory");
×
4602
      return terrno;
×
4603
    }
4604
    cJSON* bin = binDesc->child;
3,848✔
4605
    if (bin == NULL) {
3,848!
4606
      taosMemoryFree(intervals);
×
4607
      cJSON_Delete(binDesc);
×
4608
      return TSDB_CODE_FAILED;
×
4609
    }
4610
    int i = 0;
3,848✔
4611
    while (bin) {
16,938✔
4612
      intervals[i] = bin->valuedouble;
13,089✔
4613
      if (!cJSON_IsNumber(bin)) {
13,089!
4614
        taosMemoryFree(intervals);
×
4615
        cJSON_Delete(binDesc);
×
4616
        return TSDB_CODE_FAILED;
×
4617
      }
4618
      if (i != 0 && intervals[i] <= intervals[i - 1]) {
13,090!
4619
        taosMemoryFree(intervals);
×
4620
        cJSON_Delete(binDesc);
×
4621
        return TSDB_CODE_FAILED;
×
4622
      }
4623
      bin = bin->next;
13,090✔
4624
      i++;
13,090✔
4625
    }
4626
  } else {
4627
    cJSON_Delete(binDesc);
×
4628
    return TSDB_CODE_FAILED;
×
4629
  }
4630

4631
  pInfo->numOfBins = numOfBins - 1;
15,008,769✔
4632
  pInfo->normalized = normalized;
15,008,769✔
4633
  for (int32_t i = 0; i < pInfo->numOfBins; ++i) {
97,750,573✔
4634
    pInfo->bins[i].lower = intervals[i] < intervals[i + 1] ? intervals[i] : intervals[i + 1];
82,741,804✔
4635
    pInfo->bins[i].upper = intervals[i + 1] > intervals[i] ? intervals[i + 1] : intervals[i];
82,741,804✔
4636
    pInfo->bins[i].count = 0;
82,741,804✔
4637
  }
4638

4639
  taosMemoryFree(intervals);
15,008,769✔
4640
  cJSON_Delete(binDesc);
15,008,685✔
4641

4642
  return TSDB_CODE_SUCCESS;
15,008,882✔
4643
}
4644

4645
int32_t histogramFunctionSetup(SqlFunctionCtx* pCtx, SResultRowEntryInfo* pResultInfo) {
15,008,681✔
4646
  if (pResultInfo->initialized) {
15,008,681!
4647
    return TSDB_CODE_SUCCESS;
×
4648
  }
4649
  if (TSDB_CODE_SUCCESS != functionSetup(pCtx, pResultInfo)) {
15,008,681!
4650
    return TSDB_CODE_FUNC_SETUP_ERROR;
×
4651
  }
4652

4653
  SHistoFuncInfo* pInfo = GET_ROWCELL_INTERBUF(pResultInfo);
15,008,493✔
4654
  pInfo->numOfBins = 0;
15,008,493✔
4655
  pInfo->totalCount = 0;
15,008,493✔
4656
  pInfo->normalized = 0;
15,008,493✔
4657

4658
  char* binTypeStr = taosStrndup(varDataVal(pCtx->param[1].param.pz), varDataLen(pCtx->param[1].param.pz));
15,008,493!
4659
  if (binTypeStr == NULL) {
15,008,498!
4660
    return terrno;
×
4661
  }
4662
  int8_t binType = getHistogramBinType(binTypeStr);
15,008,498✔
4663
  taosMemoryFree(binTypeStr);
15,008,728!
4664

4665
  if (binType == UNKNOWN_BIN) {
15,008,514!
4666
    return TSDB_CODE_FUNC_FUNTION_PARA_VALUE;
×
4667
  }
4668
  char* binDesc = taosStrndup(varDataVal(pCtx->param[2].param.pz), varDataLen(pCtx->param[2].param.pz));
15,008,514!
4669
  if (binDesc == NULL) {
15,008,722!
4670
    return terrno;
×
4671
  }
4672
  int64_t normalized = pCtx->param[3].param.i;
15,008,722✔
4673
  if (normalized != 0 && normalized != 1) {
15,008,722!
4674
    taosMemoryFree(binDesc);
×
4675
    return TSDB_CODE_FUNC_FUNTION_PARA_VALUE;
×
4676
  }
4677
  int32_t code = getHistogramBinDesc(pInfo, binDesc, binType, (bool)normalized);
15,008,722✔
4678
  if (TSDB_CODE_SUCCESS != code) {
15,008,871!
4679
    taosMemoryFree(binDesc);
×
4680
    return code;
×
4681
  }
4682
  taosMemoryFree(binDesc);
15,008,871✔
4683

4684
  return TSDB_CODE_SUCCESS;
15,008,887✔
4685
}
4686

4687
static int32_t histogramFunctionImpl(SqlFunctionCtx* pCtx, bool isPartial) {
17,846,683✔
4688
  SHistoFuncInfo* pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
17,846,683✔
4689

4690
  SInputColumnInfoData* pInput = &pCtx->input;
17,846,683✔
4691
  SColumnInfoData*      pCol = pInput->pData[0];
17,846,683✔
4692

4693
  int32_t type = pInput->pData[0]->info.type;
17,846,683✔
4694

4695
  int32_t start = pInput->startRowIndex;
17,846,683✔
4696
  int32_t numOfRows = pInput->numOfRows;
17,846,683✔
4697

4698
  int32_t numOfElems = 0;
17,846,683✔
4699
  for (int32_t i = start; i < numOfRows + start; ++i) {
63,575,230✔
4700
    if (pCol->hasNull && colDataIsNull_f(pCol->nullbitmap, i)) {
45,728,547✔
4701
      continue;
536,836✔
4702
    }
4703

4704
    numOfElems++;
45,191,711✔
4705

4706
    char*  data = colDataGetData(pCol, i);
45,191,711!
4707
    double v;
4708
    GET_TYPED_DATA(v, double, type, data);
45,191,711!
4709

4710
    for (int32_t k = 0; k < pInfo->numOfBins; ++k) {
236,818,259✔
4711
      if (v > pInfo->bins[k].lower && v <= pInfo->bins[k].upper) {
203,609,458✔
4712
        pInfo->bins[k].count++;
11,982,910✔
4713
        pInfo->totalCount++;
11,982,910✔
4714
        break;
11,982,910✔
4715
      }
4716
    }
4717
  }
4718

4719
  if (!isPartial) {
17,846,683✔
4720
    GET_RES_INFO(pCtx)->numOfRes = pInfo->numOfBins;
12,066,305✔
4721
  } else {
4722
    GET_RES_INFO(pCtx)->numOfRes = 1;
5,780,378✔
4723
  }
4724
  return TSDB_CODE_SUCCESS;
17,846,683✔
4725
}
4726

4727
int32_t histogramFunction(SqlFunctionCtx* pCtx) { return histogramFunctionImpl(pCtx, false); }
12,066,241✔
4728

4729
int32_t histogramFunctionPartial(SqlFunctionCtx* pCtx) { return histogramFunctionImpl(pCtx, true); }
5,780,931✔
4730

4731
static void histogramTransferInfo(SHistoFuncInfo* pInput, SHistoFuncInfo* pOutput) {
2,932,237✔
4732
  pOutput->normalized = pInput->normalized;
2,932,237✔
4733
  pOutput->numOfBins = pInput->numOfBins;
2,932,237✔
4734
  pOutput->totalCount += pInput->totalCount;
2,932,237✔
4735
  for (int32_t k = 0; k < pOutput->numOfBins; ++k) {
17,594,937✔
4736
    pOutput->bins[k].lower = pInput->bins[k].lower;
14,662,700✔
4737
    pOutput->bins[k].upper = pInput->bins[k].upper;
14,662,700✔
4738
    pOutput->bins[k].count += pInput->bins[k].count;
14,662,700✔
4739
  }
4740
}
2,932,237✔
4741

4742
int32_t histogramFunctionMerge(SqlFunctionCtx* pCtx) {
2,932,237✔
4743
  SInputColumnInfoData* pInput = &pCtx->input;
2,932,237✔
4744
  SColumnInfoData*      pCol = pInput->pData[0];
2,932,237✔
4745
  if (pCol->info.type != TSDB_DATA_TYPE_BINARY) {
2,932,237!
4746
    return TSDB_CODE_FUNC_FUNTION_PARA_TYPE;
×
4747
  }
4748

4749
  SHistoFuncInfo* pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
2,932,237✔
4750

4751
  int32_t start = pInput->startRowIndex;
2,932,237✔
4752

4753
  for (int32_t i = start; i < start + pInput->numOfRows; ++i) {
5,864,474✔
4754
    char*           data = colDataGetData(pCol, i);
2,932,237!
4755
    SHistoFuncInfo* pInputInfo = (SHistoFuncInfo*)varDataVal(data);
2,932,237✔
4756
    histogramTransferInfo(pInputInfo, pInfo);
2,932,237✔
4757
  }
4758

4759
  SET_VAL(GET_RES_INFO(pCtx), pInfo->numOfBins, pInfo->numOfBins);
2,932,237!
4760
  return TSDB_CODE_SUCCESS;
2,932,237✔
4761
}
4762

4763
int32_t histogramFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
14,891,825✔
4764
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
14,891,825✔
4765
  SHistoFuncInfo*      pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
14,891,825✔
4766
  int32_t              slotId = pCtx->pExpr->base.resSchema.slotId;
14,891,825✔
4767
  SColumnInfoData*     pCol = taosArrayGet(pBlock->pDataBlock, slotId);
14,891,825✔
4768
  int32_t              code = TSDB_CODE_SUCCESS;
14,891,662✔
4769

4770
  int32_t currentRow = pBlock->info.rows;
14,891,662✔
4771
  if (NULL == pCol) {
14,891,662!
4772
    return TSDB_CODE_OUT_OF_RANGE;
×
4773
  }
4774

4775
  if (pInfo->normalized) {
14,891,662✔
4776
    for (int32_t k = 0; k < pResInfo->numOfRes; ++k) {
22,164✔
4777
      if (pInfo->totalCount != 0) {
17,445✔
4778
        pInfo->bins[k].percentage = pInfo->bins[k].count / (double)pInfo->totalCount;
10,515✔
4779
      } else {
4780
        pInfo->bins[k].percentage = 0;
6,930✔
4781
      }
4782
    }
4783
  }
4784

4785
  for (int32_t i = 0; i < pResInfo->numOfRes; ++i) {
96,901,863✔
4786
    int32_t len;
4787
    char    buf[512] = {0};
82,038,020✔
4788
    if (!pInfo->normalized) {
82,038,020✔
4789
      len = tsnprintf(varDataVal(buf), sizeof(buf) - VARSTR_HEADER_SIZE,
82,020,574✔
4790
                      "{\"lower_bin\":%g, \"upper_bin\":%g, \"count\":%" PRId64 "}", pInfo->bins[i].lower,
4791
                      pInfo->bins[i].upper, pInfo->bins[i].count);
4792
    } else {
4793
      len = tsnprintf(varDataVal(buf), sizeof(buf) - VARSTR_HEADER_SIZE,
17,446✔
4794
                      "{\"lower_bin\":%g, \"upper_bin\":%g, \"count\":%lf}", pInfo->bins[i].lower, pInfo->bins[i].upper,
4795
                      pInfo->bins[i].percentage);
4796
    }
4797
    varDataSetLen(buf, len);
82,035,858✔
4798
    code = colDataSetVal(pCol, currentRow, buf, false);
82,035,858✔
4799
    if (TSDB_CODE_SUCCESS != code) {
82,010,201!
4800
      return code;
×
4801
    }
4802
    currentRow++;
82,010,201✔
4803
  }
4804

4805
  return code;
14,863,843✔
4806
}
4807

4808
int32_t histogramPartialFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
2,964,877✔
4809
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
2,964,877✔
4810
  SHistoFuncInfo*      pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
2,964,877✔
4811
  int32_t              resultBytes = getHistogramInfoSize();
2,964,877✔
4812
  char*                res = taosMemoryCalloc(resultBytes + VARSTR_HEADER_SIZE, sizeof(char));
2,964,877!
4813

4814
  if (NULL == res) {
2,964,877!
4815
    return terrno;
×
4816
  }
4817
  (void)memcpy(varDataVal(res), pInfo, resultBytes);
2,964,877✔
4818
  varDataSetLen(res, resultBytes);
2,964,877✔
4819

4820
  int32_t          slotId = pCtx->pExpr->base.resSchema.slotId;
2,964,877✔
4821
  int32_t          code = TSDB_CODE_SUCCESS;
2,964,877✔
4822
  SColumnInfoData* pCol = taosArrayGet(pBlock->pDataBlock, slotId);
2,964,877✔
4823
  if (NULL == pCol) {
2,964,877!
4824
    code = terrno;
×
4825
    goto _exit;
×
4826
  }
4827
  code = colDataSetVal(pCol, pBlock->info.rows, res, false);
2,964,877✔
4828

4829
_exit:
2,964,877✔
4830
  taosMemoryFree(res);
2,964,877!
4831
  return code;
2,964,877✔
4832
}
4833

4834
int32_t histogramCombine(SqlFunctionCtx* pDestCtx, SqlFunctionCtx* pSourceCtx) {
×
4835
  SResultRowEntryInfo* pDResInfo = GET_RES_INFO(pDestCtx);
×
4836
  SHistoFuncInfo*      pDBuf = GET_ROWCELL_INTERBUF(pDResInfo);
×
4837

4838
  SResultRowEntryInfo* pSResInfo = GET_RES_INFO(pSourceCtx);
×
4839
  SHistoFuncInfo*      pSBuf = GET_ROWCELL_INTERBUF(pSResInfo);
×
4840

4841
  histogramTransferInfo(pSBuf, pDBuf);
×
4842
  pDResInfo->numOfRes = TMAX(pDResInfo->numOfRes, pSResInfo->numOfRes);
×
4843
  pDResInfo->isNullRes &= pSResInfo->isNullRes;
×
4844
  return TSDB_CODE_SUCCESS;
×
4845
}
4846

4847
int32_t getHLLInfoSize() { return (int32_t)sizeof(SHLLInfo); }
10,264✔
4848

4849
bool getHLLFuncEnv(SFunctionNode* UNUSED_PARAM(pFunc), SFuncExecEnv* pEnv) {
67,226✔
4850
  pEnv->calcMemSize = sizeof(SHLLInfo);
67,226✔
4851
  return true;
67,226✔
4852
}
4853

4854
static uint8_t hllCountNum(void* data, int32_t bytes, int32_t* buk) {
3,486,112✔
4855
  uint64_t hash = MurmurHash3_64(data, bytes);
3,486,112✔
4856
  int32_t  index = hash & HLL_BUCKET_MASK;
3,485,044✔
4857
  hash >>= HLL_BUCKET_BITS;
3,485,044✔
4858
  hash |= ((uint64_t)1 << HLL_DATA_BITS);
3,485,044✔
4859
  uint64_t bit = 1;
3,485,044✔
4860
  uint8_t  count = 1;
3,485,044✔
4861
  while ((hash & bit) == 0) {
7,561,039✔
4862
    count++;
4,075,995✔
4863
    bit <<= 1;
4,075,995✔
4864
  }
4865
  *buk = index;
3,485,044✔
4866
  return count;
3,485,044✔
4867
}
4868

4869
static void hllBucketHisto(uint8_t* buckets, int32_t* bucketHisto) {
262,758✔
4870
  uint64_t* word = (uint64_t*)buckets;
262,758✔
4871
  uint8_t*  bytes;
4872

4873
  for (int32_t j = 0; j < HLL_BUCKETS >> 3; j++) {
530,604,427✔
4874
    if (*word == 0) {
530,341,669✔
4875
      bucketHisto[0] += 8;
529,514,412✔
4876
    } else {
4877
      bytes = (uint8_t*)word;
827,257✔
4878
      bucketHisto[bytes[0]]++;
827,257✔
4879
      bucketHisto[bytes[1]]++;
827,257✔
4880
      bucketHisto[bytes[2]]++;
827,257✔
4881
      bucketHisto[bytes[3]]++;
827,257✔
4882
      bucketHisto[bytes[4]]++;
827,257✔
4883
      bucketHisto[bytes[5]]++;
827,257✔
4884
      bucketHisto[bytes[6]]++;
827,257✔
4885
      bucketHisto[bytes[7]]++;
827,257✔
4886
    }
4887
    word++;
530,341,669✔
4888
  }
4889
}
262,758✔
4890
static double hllTau(double x) {
262,765✔
4891
  if (x == 0. || x == 1.) return 0.;
262,765!
4892
  double zPrime;
4893
  double y = 1.0;
×
4894
  double z = 1 - x;
×
4895
  do {
4896
    x = sqrt(x);
×
4897
    zPrime = z;
×
4898
    y *= 0.5;
×
4899
    z -= pow(1 - x, 2) * y;
×
4900
  } while (zPrime != z);
×
4901
  return z / 3;
×
4902
}
4903

4904
static double hllSigma(double x) {
262,767✔
4905
  if (x == 1.0) return INFINITY;
262,767✔
4906
  double zPrime;
4907
  double y = 1;
236,601✔
4908
  double z = x;
236,601✔
4909
  do {
4910
    x *= x;
4,638,115✔
4911
    zPrime = z;
4,638,115✔
4912
    z += x * y;
4,638,115✔
4913
    y += y;
4,638,115✔
4914
  } while (zPrime != z);
4,638,115✔
4915
  return z;
236,601✔
4916
}
4917

4918
// estimate the cardinality, the algorithm refer this paper: "New cardinality estimation algorithms for HyperLogLog
4919
// sketches"
4920
static uint64_t hllCountCnt(uint8_t* buckets) {
262,730✔
4921
  double  m = HLL_BUCKETS;
262,730✔
4922
  int32_t buckethisto[64] = {0};
262,730✔
4923
  hllBucketHisto(buckets, buckethisto);
262,730✔
4924

4925
  double z = m * hllTau((m - buckethisto[HLL_DATA_BITS + 1]) / (double)m);
262,764✔
4926
  for (int j = HLL_DATA_BITS; j >= 1; --j) {
13,396,721✔
4927
    z += buckethisto[j];
13,133,954✔
4928
    z *= 0.5;
13,133,954✔
4929
  }
4930

4931
  z += m * hllSigma(buckethisto[0] / (double)m);
262,767✔
4932
  double E = (double)llroundl(HLL_ALPHA_INF * m * m / z);
262,770✔
4933

4934
  return (uint64_t)E;
262,770✔
4935
}
4936

4937
int32_t hllFunction(SqlFunctionCtx* pCtx) {
286,749✔
4938
  SHLLInfo* pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
286,749✔
4939

4940
  SInputColumnInfoData* pInput = &pCtx->input;
286,749✔
4941
  SColumnInfoData*      pCol = pInput->pData[0];
286,749✔
4942

4943
  int32_t type = pCol->info.type;
286,749✔
4944
  int32_t bytes = pCol->info.bytes;
286,749✔
4945

4946
  int32_t start = pInput->startRowIndex;
286,749✔
4947
  int32_t numOfRows = pInput->numOfRows;
286,749✔
4948

4949
  int32_t numOfElems = 0;
286,749✔
4950
  if (IS_NULL_TYPE(type)) {
286,749✔
4951
    goto _hll_over;
1,564✔
4952
  }
4953

4954
  for (int32_t i = start; i < numOfRows + start; ++i) {
4,895,559✔
4955
    if (pCol->hasNull && colDataIsNull_s(pCol, i)) {
6,464,143!
4956
      continue;
1,123,321✔
4957
    }
4958

4959
    numOfElems++;
3,487,447✔
4960

4961
    char* data = colDataGetData(pCol, i);
3,487,447!
4962
    if (IS_VAR_DATA_TYPE(type)) {
3,487,447!
4963
      bytes = varDataLen(data);
965,655✔
4964
      data = varDataVal(data);
965,655✔
4965
    }
4966

4967
    int32_t index = 0;
3,487,447✔
4968
    uint8_t count = hllCountNum(data, bytes, &index);
3,487,447✔
4969
    uint8_t oldcount = pInfo->buckets[index];
3,487,053✔
4970
    if (count > oldcount) {
3,487,053✔
4971
      pInfo->buckets[index] = count;
840,585✔
4972
    }
4973
  }
4974

4975
_hll_over:
284,791✔
4976
  pInfo->totalCount += numOfElems;
286,355✔
4977

4978
  if (pInfo->totalCount == 0 && !tsCountAlwaysReturnValue) {
286,355✔
4979
    SET_VAL(GET_RES_INFO(pCtx), 0, 1);
2,763✔
4980
  } else {
4981
    SET_VAL(GET_RES_INFO(pCtx), 1, 1);
283,592✔
4982
  }
4983

4984
  return TSDB_CODE_SUCCESS;
286,355✔
4985
}
4986

4987
static void hllTransferInfo(SHLLInfo* pInput, SHLLInfo* pOutput) {
10,547✔
4988
  for (int32_t k = 0; k < HLL_BUCKETS; ++k) {
168,598,249✔
4989
    if (pOutput->buckets[k] < pInput->buckets[k]) {
168,587,702✔
4990
      pOutput->buckets[k] = pInput->buckets[k];
70,496✔
4991
    }
4992
  }
4993
  pOutput->totalCount += pInput->totalCount;
10,547✔
4994
}
10,547✔
4995

4996
int32_t hllFunctionMerge(SqlFunctionCtx* pCtx) {
10,498✔
4997
  SInputColumnInfoData* pInput = &pCtx->input;
10,498✔
4998
  SColumnInfoData*      pCol = pInput->pData[0];
10,498✔
4999

5000
  if (IS_NULL_TYPE(pCol->info.type)) {
10,498!
5001
    SET_VAL(GET_RES_INFO(pCtx), 0, 1);
×
5002
    return TSDB_CODE_SUCCESS;
×
5003
  }
5004

5005
  if (pCol->info.type != TSDB_DATA_TYPE_BINARY) {
10,498!
5006
    return TSDB_CODE_SUCCESS;
×
5007
  }
5008

5009
  SHLLInfo* pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
10,498✔
5010

5011
  int32_t start = pInput->startRowIndex;
10,498✔
5012

5013
  for (int32_t i = start; i < start + pInput->numOfRows; ++i) {
21,044✔
5014
    if (colDataIsNull_s(pCol, i)) continue;
21,092!
5015
    char*     data = colDataGetData(pCol, i);
10,546!
5016
    SHLLInfo* pInputInfo = (SHLLInfo*)varDataVal(data);
10,546✔
5017
    hllTransferInfo(pInputInfo, pInfo);
10,546✔
5018
  }
5019

5020
  if (pInfo->totalCount == 0 && !tsCountAlwaysReturnValue) {
10,498✔
5021
    SET_VAL(GET_RES_INFO(pCtx), 0, 1);
3✔
5022
  } else {
5023
    SET_VAL(GET_RES_INFO(pCtx), 1, 1);
10,495✔
5024
  }
5025

5026
  return TSDB_CODE_SUCCESS;
10,498✔
5027
}
5028

5029
int32_t hllFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
262,731✔
5030
  SResultRowEntryInfo* pInfo = GET_RES_INFO(pCtx);
262,731✔
5031

5032
  SHLLInfo* pHllInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
262,731✔
5033
  pHllInfo->result = hllCountCnt(pHllInfo->buckets);
262,731✔
5034
  if (tsCountAlwaysReturnValue && pHllInfo->result == 0) {
262,773✔
5035
    pInfo->numOfRes = 1;
23,425✔
5036
  }
5037

5038
  return functionFinalize(pCtx, pBlock);
262,773✔
5039
}
5040

5041
int32_t hllPartialFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
10,264✔
5042
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
10,264✔
5043
  SHLLInfo*            pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
10,264✔
5044
  int32_t              resultBytes = getHLLInfoSize();
10,264✔
5045
  char*                res = taosMemoryCalloc(resultBytes + VARSTR_HEADER_SIZE, sizeof(char));
10,265!
5046

5047
  if (NULL == res) {
10,264!
5048
    return terrno;
×
5049
  }
5050
  (void)memcpy(varDataVal(res), pInfo, resultBytes);
10,264✔
5051
  varDataSetLen(res, resultBytes);
10,264✔
5052

5053
  int32_t          slotId = pCtx->pExpr->base.resSchema.slotId;
10,264✔
5054
  int32_t          code = TSDB_CODE_SUCCESS;
10,264✔
5055
  SColumnInfoData* pCol = taosArrayGet(pBlock->pDataBlock, slotId);
10,264✔
5056
  if (NULL == pCol) {
10,267!
5057
    code = terrno;
×
5058
    goto _exit;
×
5059
  }
5060

5061
  code = colDataSetVal(pCol, pBlock->info.rows, res, false);
10,267✔
5062

5063
_exit:
10,266✔
5064
  taosMemoryFree(res);
10,266!
5065
  return code;
10,268✔
5066
}
5067

5068
int32_t hllCombine(SqlFunctionCtx* pDestCtx, SqlFunctionCtx* pSourceCtx) {
1✔
5069
  SResultRowEntryInfo* pDResInfo = GET_RES_INFO(pDestCtx);
1✔
5070
  SHLLInfo*            pDBuf = GET_ROWCELL_INTERBUF(pDResInfo);
1✔
5071

5072
  SResultRowEntryInfo* pSResInfo = GET_RES_INFO(pSourceCtx);
1✔
5073
  SHLLInfo*            pSBuf = GET_ROWCELL_INTERBUF(pSResInfo);
1✔
5074

5075
  hllTransferInfo(pSBuf, pDBuf);
1✔
5076
  pDResInfo->numOfRes = TMAX(pDResInfo->numOfRes, pSResInfo->numOfRes);
1✔
5077
  pDResInfo->isNullRes &= pSResInfo->isNullRes;
1✔
5078
  return TSDB_CODE_SUCCESS;
1✔
5079
}
5080

5081
bool getStateFuncEnv(SFunctionNode* UNUSED_PARAM(pFunc), SFuncExecEnv* pEnv) {
19,214✔
5082
  pEnv->calcMemSize = sizeof(SStateInfo);
19,214✔
5083
  return true;
19,214✔
5084
}
5085

5086
static int8_t getStateOpType(char* opStr) {
139,732✔
5087
  int8_t opType;
5088
  if (strncasecmp(opStr, "LT", 2) == 0) {
139,732✔
5089
    opType = STATE_OPER_LT;
1,528✔
5090
  } else if (strncasecmp(opStr, "GT", 2) == 0) {
138,204✔
5091
    opType = STATE_OPER_GT;
26,207✔
5092
  } else if (strncasecmp(opStr, "LE", 2) == 0) {
111,997✔
5093
    opType = STATE_OPER_LE;
496✔
5094
  } else if (strncasecmp(opStr, "GE", 2) == 0) {
111,501✔
5095
    opType = STATE_OPER_GE;
2,301✔
5096
  } else if (strncasecmp(opStr, "NE", 2) == 0) {
109,200✔
5097
    opType = STATE_OPER_NE;
29,983✔
5098
  } else if (strncasecmp(opStr, "EQ", 2) == 0) {
79,217!
5099
    opType = STATE_OPER_EQ;
79,217✔
5100
  } else {
5101
    opType = STATE_OPER_INVALID;
×
5102
  }
5103

5104
  return opType;
139,732✔
5105
}
5106

5107
static bool checkStateOp(int8_t op, SColumnInfoData* pCol, int32_t index, SVariant param) {
34,871,710✔
5108
  char* data = colDataGetData(pCol, index);
34,871,710!
5109
  switch (pCol->info.type) {
34,871,710!
5110
    case TSDB_DATA_TYPE_TINYINT: {
306,048✔
5111
      int8_t v = *(int8_t*)data;
306,048✔
5112
      STATE_COMP(op, v, param);
306,048!
5113
      break;
×
5114
    }
5115
    case TSDB_DATA_TYPE_UTINYINT: {
2,880✔
5116
      uint8_t v = *(uint8_t*)data;
2,880✔
5117
      STATE_COMP(op, v, param);
2,880!
5118
      break;
×
5119
    }
5120
    case TSDB_DATA_TYPE_SMALLINT: {
13,256✔
5121
      int16_t v = *(int16_t*)data;
13,256✔
5122
      STATE_COMP(op, v, param);
13,256!
5123
      break;
×
5124
    }
5125
    case TSDB_DATA_TYPE_USMALLINT: {
2,880✔
5126
      uint16_t v = *(uint16_t*)data;
2,880✔
5127
      STATE_COMP(op, v, param);
2,880!
5128
      break;
×
5129
    }
5130
    case TSDB_DATA_TYPE_INT: {
100,474✔
5131
      int32_t v = *(int32_t*)data;
100,474✔
5132
      STATE_COMP(op, v, param);
100,474!
5133
      break;
×
5134
    }
5135
    case TSDB_DATA_TYPE_UINT: {
2,880✔
5136
      uint32_t v = *(uint32_t*)data;
2,880✔
5137
      STATE_COMP(op, v, param);
2,880!
5138
      break;
×
5139
    }
5140
    case TSDB_DATA_TYPE_BIGINT: {
21,084✔
5141
      int64_t v = *(int64_t*)data;
21,084✔
5142
      STATE_COMP(op, v, param);
21,084!
5143
      break;
×
5144
    }
5145
    case TSDB_DATA_TYPE_UBIGINT: {
2,880✔
5146
      uint64_t v = *(uint64_t*)data;
2,880✔
5147
      STATE_COMP(op, v, param);
2,880!
5148
      break;
×
5149
    }
5150
    case TSDB_DATA_TYPE_FLOAT: {
6,829,476✔
5151
      float v = *(float*)data;
6,829,476✔
5152
      STATE_COMP(op, v, param);
6,829,476!
5153
      break;
×
5154
    }
5155
    case TSDB_DATA_TYPE_DOUBLE: {
27,593,098✔
5156
      double v = *(double*)data;
27,593,098✔
5157
      STATE_COMP(op, v, param);
27,593,098!
5158
      break;
×
5159
    }
5160
    default: {
×
5161
      return false;
×
5162
    }
5163
  }
5164
  return false;
×
5165
}
5166

5167
int32_t stateCountFunction(SqlFunctionCtx* pCtx) {
30,320✔
5168
  int32_t              code = TSDB_CODE_SUCCESS;
30,320✔
5169
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
30,320✔
5170
  SStateInfo*          pInfo = GET_ROWCELL_INTERBUF(pResInfo);
30,320✔
5171

5172
  SInputColumnInfoData* pInput = &pCtx->input;
30,320✔
5173
  TSKEY*                tsList = (int64_t*)pInput->pPTS->pData;
30,320✔
5174

5175
  SColumnInfoData* pInputCol = pInput->pData[0];
30,320✔
5176

5177
  int32_t          numOfElems = 0;
30,320✔
5178
  SColumnInfoData* pOutput = (SColumnInfoData*)pCtx->pOutput;
30,320✔
5179

5180
  int8_t op = getStateOpType(varDataVal(pCtx->param[1].param.pz));
30,320✔
5181
  if (STATE_OPER_INVALID == op) {
30,320!
5182
    return 0;
×
5183
  }
5184

5185
  for (int32_t i = pInput->startRowIndex; i < pInput->numOfRows + pInput->startRowIndex; i += 1) {
7,075,464✔
5186
    if (pInfo->isPrevTsSet == true && tsList[i] == pInfo->prevTs) {
7,045,144!
5187
      return TSDB_CODE_FUNC_DUP_TIMESTAMP;
×
5188
    } else {
5189
      pInfo->prevTs = tsList[i];
7,045,144✔
5190
    }
5191

5192
    pInfo->isPrevTsSet = true;
7,045,144✔
5193
    numOfElems++;
7,045,144✔
5194

5195
    if (colDataIsNull_f(pInputCol->nullbitmap, i)) {
7,045,144✔
5196
      colDataSetNULL(pOutput, i);
81,412!
5197
      // handle selectivity
5198
      if (pCtx->subsidiaries.num > 0) {
81,412✔
5199
        code = appendSelectivityValue(pCtx, i, pCtx->offset + numOfElems - 1);
22✔
5200
        if (TSDB_CODE_SUCCESS != code) {
22!
5201
          return code;
×
5202
        }
5203
      }
5204
      continue;
81,412✔
5205
    }
5206

5207
    bool ret = checkStateOp(op, pInputCol, i, pCtx->param[2].param);
6,963,732✔
5208

5209
    int64_t output = -1;
6,963,732✔
5210
    if (ret) {
6,963,732✔
5211
      output = ++pInfo->count;
6,842,373✔
5212
    } else {
5213
      pInfo->count = 0;
121,359✔
5214
    }
5215
    code = colDataSetVal(pOutput, pCtx->offset + numOfElems - 1, (char*)&output, false);
6,963,732✔
5216
    if (TSDB_CODE_SUCCESS != code) {
6,963,732!
5217
      return code;
×
5218
    }
5219

5220
    // handle selectivity
5221
    if (pCtx->subsidiaries.num > 0) {
6,963,732✔
5222
      code = appendSelectivityValue(pCtx, i, pCtx->offset + numOfElems - 1);
3,564,344✔
5223
      if (TSDB_CODE_SUCCESS != code) {
3,564,344!
5224
        return code;
×
5225
      }
5226
    }
5227
  }
5228

5229
  pResInfo->numOfRes = numOfElems;
30,320✔
5230
  return TSDB_CODE_SUCCESS;
30,320✔
5231
}
5232

5233
int32_t stateDurationFunction(SqlFunctionCtx* pCtx) {
109,412✔
5234
  int32_t              code = TSDB_CODE_SUCCESS;
109,412✔
5235
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
109,412✔
5236
  SStateInfo*          pInfo = GET_ROWCELL_INTERBUF(pResInfo);
109,412✔
5237

5238
  SInputColumnInfoData* pInput = &pCtx->input;
109,412✔
5239
  TSKEY*                tsList = (int64_t*)pInput->pPTS->pData;
109,412✔
5240

5241
  SColumnInfoData* pInputCol = pInput->pData[0];
109,412✔
5242

5243
  int32_t          numOfElems = 0;
109,412✔
5244
  SColumnInfoData* pOutput = (SColumnInfoData*)pCtx->pOutput;
109,412✔
5245

5246
  // TODO: process timeUnit for different db precisions
5247
  int32_t timeUnit = 1;
109,412✔
5248
  if (pCtx->numOfParams == 5) {  // TODO: param number incorrect
109,412✔
5249
    timeUnit = pCtx->param[3].param.i;
108,430✔
5250
  }
5251

5252
  int8_t op = getStateOpType(varDataVal(pCtx->param[1].param.pz));
109,412✔
5253
  if (STATE_OPER_INVALID == op) {
109,412!
5254
    return TSDB_CODE_INVALID_PARA;
×
5255
  }
5256

5257
  for (int32_t i = pInput->startRowIndex; i < pInput->numOfRows + pInput->startRowIndex; i += 1) {
28,248,420✔
5258
    if (pInfo->isPrevTsSet == true && tsList[i] == pInfo->prevTs) {
28,139,026!
5259
      return TSDB_CODE_FUNC_DUP_TIMESTAMP;
×
5260
    } else {
5261
      pInfo->prevTs = tsList[i];
28,139,026✔
5262
    }
5263

5264
    pInfo->isPrevTsSet = true;
28,139,026✔
5265
    numOfElems++;
28,139,026✔
5266

5267
    if (colDataIsNull_f(pInputCol->nullbitmap, i)) {
28,139,026✔
5268
      colDataSetNULL(pOutput, i);
229,292!
5269
      // handle selectivity
5270
      if (pCtx->subsidiaries.num > 0) {
229,292✔
5271
        code = appendSelectivityValue(pCtx, i, pCtx->offset + numOfElems - 1);
30✔
5272
        if (TSDB_CODE_SUCCESS != code) {
30!
5273
          return code;
×
5274
        }
5275
      }
5276
      continue;
229,292✔
5277
    }
5278

5279
    bool    ret = checkStateOp(op, pInputCol, i, pCtx->param[2].param);
27,909,734✔
5280
    int64_t output = -1;
27,909,588✔
5281
    if (ret) {
27,909,588✔
5282
      if (pInfo->durationStart == 0) {
2,336,232✔
5283
        output = 0;
1,338,054✔
5284
        pInfo->durationStart = tsList[i];
1,338,054✔
5285
      } else {
5286
        output = (tsList[i] - pInfo->durationStart) / timeUnit;
998,178✔
5287
      }
5288
    } else {
5289
      pInfo->durationStart = 0;
25,573,356✔
5290
    }
5291
    code = colDataSetVal(pOutput, pCtx->offset + numOfElems - 1, (char*)&output, false);
27,909,588✔
5292
    if (TSDB_CODE_SUCCESS != code) {
27,909,716!
5293
      return code;
×
5294
    }
5295

5296
    // handle selectivity
5297
    if (pCtx->subsidiaries.num > 0) {
27,909,716✔
5298
      code = appendSelectivityValue(pCtx, i, pCtx->offset + numOfElems - 1);
16,271,940✔
5299
      if (TSDB_CODE_SUCCESS != code) {
16,271,940!
5300
        return code;
×
5301
      }
5302
    }
5303
  }
5304

5305
  pResInfo->numOfRes = numOfElems;
109,394✔
5306
  return TSDB_CODE_SUCCESS;
109,394✔
5307
}
5308

5309
bool getCsumFuncEnv(SFunctionNode* UNUSED_PARAM(pFunc), SFuncExecEnv* pEnv) {
15,642✔
5310
  pEnv->calcMemSize = sizeof(SSumRes);
15,642✔
5311
  return true;
15,642✔
5312
}
5313

5314
int32_t csumFunction(SqlFunctionCtx* pCtx) {
28,979✔
5315
  int32_t              code = TSDB_CODE_SUCCESS;
28,979✔
5316
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
28,979✔
5317
  SSumRes*             pSumRes = GET_ROWCELL_INTERBUF(pResInfo);
28,979✔
5318

5319
  SInputColumnInfoData* pInput = &pCtx->input;
28,979✔
5320
  TSKEY*                tsList = (int64_t*)pInput->pPTS->pData;
28,979✔
5321

5322
  SColumnInfoData* pInputCol = pInput->pData[0];
28,979✔
5323
  SColumnInfoData* pOutput = (SColumnInfoData*)pCtx->pOutput;
28,979✔
5324

5325
  int32_t numOfElems = 0;
28,979✔
5326
  int32_t type = pInputCol->info.type;
28,979✔
5327
  int32_t startOffset = pCtx->offset;
28,979✔
5328
  for (int32_t i = pInput->startRowIndex; i < pInput->numOfRows + pInput->startRowIndex; i += 1) {
4,006,414✔
5329
    if (pSumRes->isPrevTsSet == true && tsList[i] == pSumRes->prevTs) {
3,977,453✔
5330
      return TSDB_CODE_FUNC_DUP_TIMESTAMP;
18✔
5331
    } else {
5332
      pSumRes->prevTs = tsList[i];
3,977,435✔
5333
    }
5334
    pSumRes->isPrevTsSet = true;
3,977,435✔
5335

5336
    int32_t pos = startOffset + numOfElems;
3,977,435✔
5337
    if (colDataIsNull_f(pInputCol->nullbitmap, i)) {
3,977,435✔
5338
      // colDataSetNULL(pOutput, i);
5339
      continue;
672,173✔
5340
    }
5341

5342
    char* data = colDataGetData(pInputCol, i);
3,305,262!
5343
    if (IS_SIGNED_NUMERIC_TYPE(type)) {
6,582,344!
5344
      int64_t v;
5345
      GET_TYPED_DATA(v, int64_t, type, data);
3,277,082!
5346
      pSumRes->isum += v;
3,277,082✔
5347
      code = colDataSetVal(pOutput, pos, (char*)&pSumRes->isum, false);
3,277,082✔
5348
      if (TSDB_CODE_SUCCESS != code) {
3,277,082!
5349
        return code;
×
5350
      }
5351
    } else if (IS_UNSIGNED_NUMERIC_TYPE(type)) {
28,860!
5352
      uint64_t v;
5353
      GET_TYPED_DATA(v, uint64_t, type, data);
680!
5354
      pSumRes->usum += v;
680✔
5355
      code = colDataSetVal(pOutput, pos, (char*)&pSumRes->usum, false);
680✔
5356
      if (TSDB_CODE_SUCCESS != code) {
680!
5357
        return code;
×
5358
      }
5359
    } else if (IS_FLOAT_TYPE(type)) {
27,500!
5360
      double v;
5361
      GET_TYPED_DATA(v, double, type, data);
27,500!
5362
      pSumRes->dsum += v;
27,500✔
5363
      // check for overflow
5364
      if (isinf(pSumRes->dsum) || isnan(pSumRes->dsum)) {
27,500!
5365
        colDataSetNULL(pOutput, pos);
8!
5366
      } else {
5367
        code = colDataSetVal(pOutput, pos, (char*)&pSumRes->dsum, false);
27,492✔
5368
        if (TSDB_CODE_SUCCESS != code) {
27,492!
5369
          return code;
×
5370
        }
5371
      }
5372
    }
5373

5374
    // handle selectivity
5375
    if (pCtx->subsidiaries.num > 0) {
3,305,262✔
5376
      code = appendSelectivityValue(pCtx, i, pos);
2,010,604✔
5377
      if (TSDB_CODE_SUCCESS != code) {
2,010,604!
5378
        return code;
×
5379
      }
5380
    }
5381

5382
    numOfElems++;
3,305,262✔
5383
  }
5384

5385
  pResInfo->numOfRes = numOfElems;
28,961✔
5386
  return TSDB_CODE_SUCCESS;
28,961✔
5387
}
5388

5389
bool getMavgFuncEnv(SFunctionNode* UNUSED_PARAM(pFunc), SFuncExecEnv* pEnv) {
13,588✔
5390
  pEnv->calcMemSize = sizeof(SMavgInfo) + MAVG_MAX_POINTS_NUM * sizeof(double);
13,588✔
5391
  return true;
13,588✔
5392
}
5393

5394
int32_t mavgFunctionSetup(SqlFunctionCtx* pCtx, SResultRowEntryInfo* pResultInfo) {
252,316✔
5395
  if (pResultInfo->initialized) {
252,316✔
5396
    return TSDB_CODE_SUCCESS;
238,038✔
5397
  }
5398
  if (TSDB_CODE_SUCCESS != functionSetup(pCtx, pResultInfo)) {
14,278!
5399
    return TSDB_CODE_FUNC_SETUP_ERROR;
×
5400
  }
5401

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

5413
  return TSDB_CODE_SUCCESS;
14,278✔
5414
}
5415

5416
int32_t mavgFunction(SqlFunctionCtx* pCtx) {
238,727✔
5417
  int32_t              code = TSDB_CODE_SUCCESS;
238,727✔
5418
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
238,727✔
5419
  SMavgInfo*           pInfo = GET_ROWCELL_INTERBUF(pResInfo);
238,727✔
5420

5421
  SInputColumnInfoData* pInput = &pCtx->input;
238,727✔
5422
  TSKEY*                tsList = (int64_t*)pInput->pPTS->pData;
238,727✔
5423

5424
  SColumnInfoData* pInputCol = pInput->pData[0];
238,727✔
5425
  SColumnInfoData* pTsOutput = pCtx->pTsOutput;
238,727✔
5426
  SColumnInfoData* pOutput = (SColumnInfoData*)pCtx->pOutput;
238,727✔
5427

5428
  int32_t numOfElems = 0;
238,727✔
5429
  int32_t type = pInputCol->info.type;
238,727✔
5430
  int32_t startOffset = pCtx->offset;
238,727✔
5431
  for (int32_t i = pInput->startRowIndex; i < pInput->numOfRows + pInput->startRowIndex; i += 1) {
59,080,779✔
5432
    if (pInfo->isPrevTsSet == true && tsList[i] == pInfo->prevTs) {
58,841,957!
5433
      return TSDB_CODE_FUNC_DUP_TIMESTAMP;
×
5434
    } else {
5435
      pInfo->prevTs = tsList[i];
58,841,957✔
5436
    }
5437
    pInfo->isPrevTsSet = true;
58,841,957✔
5438

5439
    int32_t pos = startOffset + numOfElems;
58,841,957✔
5440
    if (colDataIsNull_f(pInputCol->nullbitmap, i)) {
58,841,957✔
5441
      // colDataSetNULL(pOutput, i);
5442
      continue;
104,195✔
5443
    }
5444

5445
    char*  data = colDataGetData(pInputCol, i);
58,737,762!
5446
    double v;
5447
    GET_TYPED_DATA(v, double, type, data);
58,737,762!
5448

5449
    if (!pInfo->pointsMeet && (pInfo->pos < pInfo->numOfPoints - 1)) {
58,737,762✔
5450
      pInfo->points[pInfo->pos] = v;
4,961,129✔
5451
      pInfo->sum += v;
4,961,129✔
5452
    } else {
5453
      if (!pInfo->pointsMeet && (pInfo->pos == pInfo->numOfPoints - 1)) {
53,776,633!
5454
        pInfo->sum += v;
11,530✔
5455
        pInfo->pointsMeet = true;
11,530✔
5456
      } else {
5457
        pInfo->sum = pInfo->sum + v - pInfo->points[pInfo->pos];
53,765,103✔
5458
      }
5459

5460
      pInfo->points[pInfo->pos] = v;
53,776,633✔
5461
      double result = pInfo->sum / pInfo->numOfPoints;
53,776,633✔
5462
      // check for overflow
5463
      if (isinf(result) || isnan(result)) {
53,776,633!
5464
        colDataSetNULL(pOutput, pos);
×
5465
      } else {
5466
        code = colDataSetVal(pOutput, pos, (char*)&result, false);
53,776,886✔
5467
        if (TSDB_CODE_SUCCESS != code) {
53,776,981!
5468
          return code;
×
5469
        }
5470
      }
5471

5472
      // handle selectivity
5473
      if (pCtx->subsidiaries.num > 0) {
53,776,728✔
5474
        code = appendSelectivityValue(pCtx, i, pos);
33,685,615✔
5475
        if (TSDB_CODE_SUCCESS != code) {
33,685,615!
5476
          return code;
×
5477
        }
5478
      }
5479

5480
      numOfElems++;
53,776,728✔
5481
    }
5482

5483
    pInfo->pos++;
58,737,857✔
5484
    if (pInfo->pos == pInfo->numOfPoints) {
58,737,857✔
5485
      pInfo->pos = 0;
376,324✔
5486
    }
5487
  }
5488

5489
  pResInfo->numOfRes = numOfElems;
238,822✔
5490
  return TSDB_CODE_SUCCESS;
238,822✔
5491
}
5492

5493
static SSampleInfo* getSampleOutputInfo(SqlFunctionCtx* pCtx) {
24,993,806✔
5494
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
24,993,806✔
5495
  SSampleInfo*         pInfo = GET_ROWCELL_INTERBUF(pResInfo);
24,993,806✔
5496

5497
  pInfo->data = (char*)pInfo + sizeof(SSampleInfo);
24,993,806✔
5498
  pInfo->tuplePos = (STuplePos*)((char*)pInfo + sizeof(SSampleInfo) + pInfo->samples * pInfo->colBytes);
24,993,806✔
5499

5500
  return pInfo;
24,993,806✔
5501
}
5502

5503
bool getSampleFuncEnv(SFunctionNode* pFunc, SFuncExecEnv* pEnv) {
30,118✔
5504
  SColumnNode* pCol = (SColumnNode*)nodesListGetNode(pFunc->pParameterList, 0);
30,118✔
5505
  SValueNode*  pVal = (SValueNode*)nodesListGetNode(pFunc->pParameterList, 1);
30,129✔
5506
  int32_t      numOfSamples = pVal->datum.i;
30,132✔
5507
  pEnv->calcMemSize = sizeof(SSampleInfo) + numOfSamples * (pCol->node.resType.bytes + sizeof(STuplePos));
30,132✔
5508
  return true;
30,132✔
5509
}
5510

5511
int32_t sampleFunctionSetup(SqlFunctionCtx* pCtx, SResultRowEntryInfo* pResultInfo) {
11,357,271✔
5512
  if (pResultInfo->initialized) {
11,357,271!
5513
    return TSDB_CODE_SUCCESS;
×
5514
  }
5515
  if (TSDB_CODE_SUCCESS != functionSetup(pCtx, pResultInfo)) {
11,357,271!
5516
    return TSDB_CODE_FUNC_SETUP_ERROR;
×
5517
  }
5518

5519
  taosSeedRand(taosSafeRand());
11,357,274✔
5520

5521
  SSampleInfo* pInfo = GET_ROWCELL_INTERBUF(pResultInfo);
11,357,277✔
5522
  pInfo->samples = pCtx->param[1].param.i;
11,357,277✔
5523
  pInfo->totalPoints = 0;
11,357,277✔
5524
  pInfo->numSampled = 0;
11,357,277✔
5525
  pInfo->colType = pCtx->resDataInfo.type;
11,357,277✔
5526
  pInfo->colBytes = pCtx->resDataInfo.bytes;
11,357,277✔
5527
  pInfo->nullTuplePos.pageId = -1;
11,357,277✔
5528
  pInfo->nullTupleSaved = false;
11,357,277✔
5529
  pInfo->data = (char*)pInfo + sizeof(SSampleInfo);
11,357,277✔
5530
  pInfo->tuplePos = (STuplePos*)((char*)pInfo + sizeof(SSampleInfo) + pInfo->samples * pInfo->colBytes);
11,357,277✔
5531

5532
  return TSDB_CODE_SUCCESS;
11,357,277✔
5533
}
5534

5535
static void sampleAssignResult(SSampleInfo* pInfo, char* data, int32_t index) {
31,533,026✔
5536
  assignVal(pInfo->data + index * pInfo->colBytes, data, pInfo->colBytes, pInfo->colType);
31,533,026✔
5537
}
31,533,050✔
5538

5539
static int32_t doReservoirSample(SqlFunctionCtx* pCtx, SSampleInfo* pInfo, char* data, int32_t index) {
35,204,823✔
5540
  pInfo->totalPoints++;
35,204,823✔
5541
  if (pInfo->numSampled < pInfo->samples) {
35,204,823✔
5542
    sampleAssignResult(pInfo, data, pInfo->numSampled);
28,472,554✔
5543
    if (pCtx->subsidiaries.num > 0) {
28,472,557✔
5544
      int32_t code = saveTupleData(pCtx, index, pCtx->pSrcBlock, &pInfo->tuplePos[pInfo->numSampled]);
807,041✔
5545
      if (code != TSDB_CODE_SUCCESS) {
806,984!
5546
        return code;
×
5547
      }
5548
    }
5549
    pInfo->numSampled++;
28,472,500✔
5550
  } else {
5551
    int32_t j = taosRand() % (pInfo->totalPoints);
6,732,269✔
5552
    if (j < pInfo->samples) {
6,732,577✔
5553
      sampleAssignResult(pInfo, data, j);
3,060,548✔
5554
      if (pCtx->subsidiaries.num > 0) {
3,060,541✔
5555
        int32_t code = updateTupleData(pCtx, index, pCtx->pSrcBlock, &pInfo->tuplePos[j]);
584,193✔
5556
        if (code != TSDB_CODE_SUCCESS) {
584,064!
5557
          return code;
×
5558
        }
5559
      }
5560
    }
5561
  }
5562

5563
  return TSDB_CODE_SUCCESS;
35,204,941✔
5564
}
5565

5566
int32_t sampleFunction(SqlFunctionCtx* pCtx) {
13,726,495✔
5567
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
13,726,495✔
5568
  SSampleInfo*         pInfo = getSampleOutputInfo(pCtx);
13,726,495✔
5569

5570
  SInputColumnInfoData* pInput = &pCtx->input;
13,726,495✔
5571

5572
  SColumnInfoData* pInputCol = pInput->pData[0];
13,726,495✔
5573
  for (int32_t i = pInput->startRowIndex; i < pInput->numOfRows + pInput->startRowIndex; i += 1) {
49,409,287✔
5574
    if (colDataIsNull_s(pInputCol, i)) {
71,363,702✔
5575
      continue;
477,965✔
5576
    }
5577

5578
    char*   data = colDataGetData(pInputCol, i);
35,203,886!
5579
    int32_t code = doReservoirSample(pCtx, pInfo, data, i);
35,203,886✔
5580
    if (code != TSDB_CODE_SUCCESS) {
35,204,827!
5581
      return code;
×
5582
    }
5583
  }
5584

5585
  if (pInfo->numSampled == 0 && pCtx->subsidiaries.num > 0 && !pInfo->nullTupleSaved) {
13,727,436✔
5586
    int32_t code = saveTupleData(pCtx, pInput->startRowIndex, pCtx->pSrcBlock, &pInfo->nullTuplePos);
21✔
5587
    if (code != TSDB_CODE_SUCCESS) {
21!
5588
      return code;
×
5589
    }
5590
    pInfo->nullTupleSaved = true;
21✔
5591
  }
5592

5593
  SET_VAL(pResInfo, pInfo->numSampled, pInfo->numSampled);
13,727,436✔
5594
  return TSDB_CODE_SUCCESS;
13,727,436✔
5595
}
5596

5597
int32_t sampleFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
11,267,315✔
5598
  int32_t              code = TSDB_CODE_SUCCESS;
11,267,315✔
5599
  SResultRowEntryInfo* pEntryInfo = GET_RES_INFO(pCtx);
11,267,315✔
5600

5601
  SSampleInfo* pInfo = getSampleOutputInfo(pCtx);
11,267,315✔
5602
  pEntryInfo->complete = true;
11,267,315✔
5603

5604
  int32_t          slotId = pCtx->pExpr->base.resSchema.slotId;
11,267,315✔
5605
  SColumnInfoData* pCol = taosArrayGet(pBlock->pDataBlock, slotId);
11,267,315✔
5606
  if (NULL == pCol) {
11,267,315!
5607
    return TSDB_CODE_OUT_OF_RANGE;
×
5608
  }
5609

5610
  int32_t currentRow = pBlock->info.rows;
11,267,315✔
5611
  if (pInfo->numSampled == 0) {
11,267,315✔
5612
    colDataSetNULL(pCol, currentRow);
2,694✔
5613
    code = setSelectivityValue(pCtx, pBlock, &pInfo->nullTuplePos, currentRow);
2,694✔
5614
    return code;
2,694✔
5615
  }
5616
  for (int32_t i = 0; i < pInfo->numSampled; ++i) {
39,052,469✔
5617
    code = colDataSetVal(pCol, currentRow + i, pInfo->data + i * pInfo->colBytes, false);
27,788,156✔
5618
    if (TSDB_CODE_SUCCESS != code) {
27,787,827!
5619
      return code;
×
5620
    }
5621
    code = setSelectivityValue(pCtx, pBlock, &pInfo->tuplePos[i], currentRow + i);
27,787,827✔
5622
    if (TSDB_CODE_SUCCESS != code) {
27,787,848!
5623
      return code;
×
5624
    }
5625
  }
5626

5627
  return code;
11,264,313✔
5628
}
5629

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

5640
int32_t tailFunctionSetup(SqlFunctionCtx* pCtx, SResultRowEntryInfo* pResultInfo) {
×
5641
#if 0
5642
  if (!functionSetup(pCtx, pResultInfo)) {
5643
    return false;
5644
  }
5645

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

5661
  pInfo->pItems = (STailItem**)((char*)pInfo + sizeof(STailInfo));
5662
  char* pItem = (char*)pInfo->pItems + pInfo->numOfPoints * POINTER_BYTES;
5663

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

5671
  return TSDB_CODE_SUCCESS;
×
5672
}
5673

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

5686
#if 0
5687
static int32_t tailCompFn(const void* p1, const void* p2, const void* param) {
5688
  STailItem* d1 = *(STailItem**)p1;
5689
  STailItem* d2 = *(STailItem**)p2;
5690
  return compareInt64Val(&d1->timestamp, &d2->timestamp);
5691
}
5692

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

5706
int32_t tailFunction(SqlFunctionCtx* pCtx) {
×
5707
#if 0
5708
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
5709
  STailInfo*           pInfo = GET_ROWCELL_INTERBUF(pResInfo);
5710

5711
  SInputColumnInfoData* pInput = &pCtx->input;
5712
  TSKEY*                tsList = (int64_t*)pInput->pPTS->pData;
5713

5714
  SColumnInfoData* pInputCol = pInput->pData[0];
5715
  SColumnInfoData* pOutput = (SColumnInfoData*)pCtx->pOutput;
5716

5717
  int32_t startOffset = pCtx->offset;
5718
  if (pInfo->offset >= pInput->numOfRows) {
5719
    return 0;
5720
  } else {
5721
    pInfo->numOfPoints = TMIN(pInfo->numOfPoints, pInput->numOfRows - pInfo->offset);
5722
  }
5723
  for (int32_t i = pInput->startRowIndex; i < pInput->numOfRows + pInput->startRowIndex - pInfo->offset; i += 1) {
5724
    char* data = colDataGetData(pInputCol, i);
5725
    doTailAdd(pInfo, data, tsList[i], colDataIsNull_s(pInputCol, i));
5726
  }
5727

5728
  taosqsort(pInfo->pItems, pInfo->numOfPoints, POINTER_BYTES, NULL, tailCompFn);
5729

5730
  for (int32_t i = 0; i < pInfo->numOfPoints; ++i) {
5731
    int32_t    pos = startOffset + i;
5732
    STailItem* pItem = pInfo->pItems[i];
5733
    if (pItem->isNull) {
5734
      colDataSetNULL(pOutput, pos);
5735
    } else {
5736
      colDataSetVal(pOutput, pos, pItem->data, false);
5737
    }
5738
  }
5739

5740
  return pInfo->numOfPoints;
5741
#endif
5742
  return 0;
×
5743
}
5744

5745
int32_t tailFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
×
5746
#if 0
5747
  SResultRowEntryInfo* pEntryInfo = GET_RES_INFO(pCtx);
5748
  STailInfo*           pInfo = GET_ROWCELL_INTERBUF(pEntryInfo);
5749
  pEntryInfo->complete = true;
5750

5751
  int32_t type = pCtx->input.pData[0]->info.type;
5752
  int32_t slotId = pCtx->pExpr->base.resSchema.slotId;
5753

5754
  SColumnInfoData* pCol = taosArrayGet(pBlock->pDataBlock, slotId);
5755

5756
  // todo assign the tag value and the corresponding row data
5757
  int32_t currentRow = pBlock->info.rows;
5758
  for (int32_t i = 0; i < pEntryInfo->numOfRes; ++i) {
5759
    STailItem* pItem = pInfo->pItems[i];
5760
    colDataSetVal(pCol, currentRow, pItem->data, false);
5761
    currentRow += 1;
5762
  }
5763

5764
  return pEntryInfo->numOfRes;
5765
#endif
5766
  return 0;
×
5767
}
5768

5769
bool getUniqueFuncEnv(SFunctionNode* pFunc, SFuncExecEnv* pEnv) {
×
5770
#if 0
5771
  pEnv->calcMemSize = sizeof(SUniqueInfo) + UNIQUE_MAX_RESULT_SIZE;
5772
#endif
5773
  return true;
×
5774
}
5775

5776
int32_t uniqueFunctionSetup(SqlFunctionCtx* pCtx, SResultRowEntryInfo* pResInfo) {
×
5777
#if 0
5778
  if (!functionSetup(pCtx, pResInfo)) {
5779
    return false;
5780
  }
5781

5782
  SUniqueInfo* pInfo = GET_ROWCELL_INTERBUF(pResInfo);
5783
  pInfo->numOfPoints = 0;
5784
  pInfo->colType = pCtx->resDataInfo.type;
5785
  pInfo->colBytes = pCtx->resDataInfo.bytes;
5786
  if (pInfo->pHash != NULL) {
5787
    taosHashClear(pInfo->pHash);
5788
  } else {
5789
    pInfo->pHash = taosHashInit(64, taosGetDefaultHashFunction(TSDB_DATA_TYPE_BINARY), true, HASH_NO_LOCK);
5790
  }
5791
#endif
5792
  return TSDB_CODE_SUCCESS;
×
5793
}
5794

5795
#if 0
5796
static void doUniqueAdd(SUniqueInfo* pInfo, char* data, TSKEY ts, bool isNull) {
5797
  // handle null elements
5798
  if (isNull == true) {
5799
    int32_t      size = sizeof(SUniqueItem) + pInfo->colBytes;
5800
    SUniqueItem* pItem = (SUniqueItem*)(pInfo->pItems + pInfo->numOfPoints * size);
5801
    if (pInfo->hasNull == false && pItem->isNull == false) {
5802
      pItem->timestamp = ts;
5803
      pItem->isNull = true;
5804
      pInfo->numOfPoints++;
5805
      pInfo->hasNull = true;
5806
    } else if (pItem->timestamp > ts && pItem->isNull == true) {
5807
      pItem->timestamp = ts;
5808
    }
5809
    return;
5810
  }
5811

5812
  int32_t      hashKeyBytes = IS_VAR_DATA_TYPE(pInfo->colType) ? varDataTLen(data) : pInfo->colBytes;
5813
  SUniqueItem* pHashItem = taosHashGet(pInfo->pHash, data, hashKeyBytes);
5814
  if (pHashItem == NULL) {
5815
    int32_t      size = sizeof(SUniqueItem) + pInfo->colBytes;
5816
    SUniqueItem* pItem = (SUniqueItem*)(pInfo->pItems + pInfo->numOfPoints * size);
5817
    pItem->timestamp = ts;
5818
    memcpy(pItem->data, data, pInfo->colBytes);
5819

5820
    taosHashPut(pInfo->pHash, data, hashKeyBytes, (char*)pItem, sizeof(SUniqueItem*));
5821
    pInfo->numOfPoints++;
5822
  } else if (pHashItem->timestamp > ts) {
5823
    pHashItem->timestamp = ts;
5824
  }
5825
}
5826
#endif
5827

5828
int32_t uniqueFunction(SqlFunctionCtx* pCtx) {
×
5829
#if 0
5830
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
5831
  SUniqueInfo*         pInfo = GET_ROWCELL_INTERBUF(pResInfo);
5832

5833
  SInputColumnInfoData* pInput = &pCtx->input;
5834
  TSKEY*                tsList = (int64_t*)pInput->pPTS->pData;
5835

5836
  SColumnInfoData* pInputCol = pInput->pData[0];
5837
  SColumnInfoData* pTsOutput = pCtx->pTsOutput;
5838
  SColumnInfoData* pOutput = (SColumnInfoData*)pCtx->pOutput;
5839

5840
  int32_t startOffset = pCtx->offset;
5841
  for (int32_t i = pInput->startRowIndex; i < pInput->numOfRows + pInput->startRowIndex; ++i) {
5842
    char* data = colDataGetData(pInputCol, i);
5843
    doUniqueAdd(pInfo, data, tsList[i], colDataIsNull_s(pInputCol, i));
5844

5845
    if (sizeof(SUniqueInfo) + pInfo->numOfPoints * (sizeof(SUniqueItem) + pInfo->colBytes) >= UNIQUE_MAX_RESULT_SIZE) {
5846
      taosHashCleanup(pInfo->pHash);
5847
      return 0;
5848
    }
5849
  }
5850

5851
  for (int32_t i = 0; i < pInfo->numOfPoints; ++i) {
5852
    SUniqueItem* pItem = (SUniqueItem*)(pInfo->pItems + i * (sizeof(SUniqueItem) + pInfo->colBytes));
5853
    if (pItem->isNull == true) {
5854
      colDataSetNULL(pOutput, i);
5855
    } else {
5856
      colDataSetVal(pOutput, i, pItem->data, false);
5857
    }
5858
    if (pTsOutput != NULL) {
5859
      colDataSetInt64(pTsOutput, i, &pItem->timestamp);
5860
    }
5861
  }
5862

5863
  return pInfo->numOfPoints;
5864
#endif
5865
  return 0;
×
5866
}
5867

5868
bool getModeFuncEnv(SFunctionNode* pFunc, SFuncExecEnv* pEnv) {
24,855✔
5869
  pEnv->calcMemSize = sizeof(SModeInfo);
24,855✔
5870
  return true;
24,855✔
5871
}
5872

5873
int32_t modeFunctionSetup(SqlFunctionCtx* pCtx, SResultRowEntryInfo* pResInfo) {
25,675✔
5874
  if (pResInfo->initialized) {
25,675!
5875
    return TSDB_CODE_SUCCESS;
×
5876
  }
5877
  if (TSDB_CODE_SUCCESS != functionSetup(pCtx, pResInfo)) {
25,675!
5878
    return TSDB_CODE_FUNC_SETUP_ERROR;
×
5879
  }
5880

5881
  SModeInfo* pInfo = GET_ROWCELL_INTERBUF(pResInfo);
25,675✔
5882
  pInfo->colType = pCtx->resDataInfo.type;
25,675✔
5883
  pInfo->colBytes = pCtx->resDataInfo.bytes;
25,675✔
5884
  if (pInfo->pHash != NULL) {
25,675!
5885
    taosHashClear(pInfo->pHash);
×
5886
  } else {
5887
    pInfo->pHash = taosHashInit(64, taosGetDefaultHashFunction(TSDB_DATA_TYPE_BINARY), true, HASH_NO_LOCK);
25,675✔
5888
    if (NULL == pInfo->pHash) {
25,675!
5889
      return terrno;
×
5890
    }
5891
  }
5892
  pInfo->nullTupleSaved = false;
25,675✔
5893
  pInfo->nullTuplePos.pageId = -1;
25,675✔
5894

5895
  pInfo->buf = taosMemoryMalloc(pInfo->colBytes);
25,675!
5896
  if (NULL == pInfo->buf) {
25,675!
5897
    taosHashCleanup(pInfo->pHash);
×
5898
    pInfo->pHash = NULL;
×
5899
    return terrno;
×
5900
  }
5901
  pCtx->needCleanup = true;
25,675✔
5902
  return TSDB_CODE_SUCCESS;
25,675✔
5903
}
5904

5905
static void modeFunctionCleanup(SModeInfo* pInfo) {
25,675✔
5906
  taosHashCleanup(pInfo->pHash);
25,675✔
5907
  pInfo->pHash = NULL;
25,675✔
5908
  taosMemoryFreeClear(pInfo->buf);
25,675!
5909
}
25,675✔
5910

5911
void modeFunctionCleanupExt(SqlFunctionCtx* pCtx) {
×
5912
  if (pCtx == NULL || GET_RES_INFO(pCtx) == NULL || GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx)) == NULL) {
×
5913
    return;
×
5914
  }
5915
  modeFunctionCleanup(GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx)));
×
5916
}
5917

5918
static int32_t saveModeTupleData(SqlFunctionCtx* pCtx, char* data, SModeInfo* pInfo, STuplePos* pPos) {
49,200,427✔
5919
  if (IS_VAR_DATA_TYPE(pInfo->colType)) {
49,200,427!
5920
    if (pInfo->colType == TSDB_DATA_TYPE_JSON) {
5,674,486!
5921
      (void)memcpy(pInfo->buf, data, getJsonValueLen(data));
×
5922
    } else {
5923
      (void)memcpy(pInfo->buf, data, varDataTLen(data));
5,674,486✔
5924
    }
5925
  } else {
5926
    (void)memcpy(pInfo->buf, data, pInfo->colBytes);
43,525,941✔
5927
  }
5928

5929
  return doSaveTupleData(&pCtx->saveHandle, pInfo->buf, pInfo->colBytes, NULL, pPos, pCtx->pStore);
49,200,427✔
5930
}
5931

5932
static int32_t doModeAdd(SModeInfo* pInfo, int32_t rowIndex, SqlFunctionCtx* pCtx, char* data) {
123,985,051✔
5933
  int32_t code = TSDB_CODE_SUCCESS;
123,985,051✔
5934
  int32_t hashKeyBytes;
5935
  if (IS_VAR_DATA_TYPE(pInfo->colType)) {
123,985,051!
5936
    if (pInfo->colType == TSDB_DATA_TYPE_JSON) {
5,674,974!
5937
      hashKeyBytes = getJsonValueLen(data);
×
5938
    } else {
5939
      hashKeyBytes = varDataTLen(data);
5,674,974✔
5940
    }
5941
  } else {
5942
    hashKeyBytes = pInfo->colBytes;
118,310,077✔
5943
  }
5944

5945
  SModeItem* pHashItem = (SModeItem*)taosHashGet(pInfo->pHash, data, hashKeyBytes);
123,985,466✔
5946
  if (pHashItem == NULL) {
123,984,290✔
5947
    int32_t   size = sizeof(SModeItem);
49,200,428✔
5948
    SModeItem item = {0};
49,200,428✔
5949

5950
    item.count += 1;
49,200,428✔
5951
    code = saveModeTupleData(pCtx, data, pInfo, &item.dataPos);
49,200,428✔
5952
    if (code != TSDB_CODE_SUCCESS) {
49,199,280!
5953
      return code;
×
5954
    }
5955

5956
    if (pCtx->subsidiaries.num > 0) {
49,199,280✔
5957
      code = saveTupleData(pCtx, rowIndex, pCtx->pSrcBlock, &item.tuplePos);
25,333,936✔
5958
      if (code != TSDB_CODE_SUCCESS) {
25,333,936!
5959
        return code;
×
5960
      }
5961
    }
5962

5963
    code = taosHashPut(pInfo->pHash, data, hashKeyBytes, &item, sizeof(SModeItem));
49,199,280✔
5964
    if (code != TSDB_CODE_SUCCESS) {
49,201,511!
5965
      return code;
×
5966
    }
5967
  } else {
5968
    pHashItem->count += 1;
74,783,862✔
5969
    if (pCtx->subsidiaries.num > 0) {
74,783,862✔
5970
      code = updateTupleData(pCtx, rowIndex, pCtx->pSrcBlock, &pHashItem->tuplePos);
55,654,450✔
5971
      if (code != TSDB_CODE_SUCCESS) {
55,654,450!
5972
        return code;
×
5973
      }
5974
    }
5975
  }
5976

5977
  return code;
123,985,373✔
5978
}
5979

5980
int32_t modeFunction(SqlFunctionCtx* pCtx) {
2,438,973✔
5981
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
2,438,973✔
5982
  SModeInfo*           pInfo = GET_ROWCELL_INTERBUF(pResInfo);
2,438,973✔
5983

5984
  SInputColumnInfoData* pInput = &pCtx->input;
2,438,973✔
5985

5986
  SColumnInfoData* pInputCol = pInput->pData[0];
2,438,973✔
5987
  SColumnInfoData* pOutput = (SColumnInfoData*)pCtx->pOutput;
2,438,973✔
5988

5989
  int32_t numOfElems = 0;
2,438,973✔
5990
  int32_t startOffset = pCtx->offset;
2,438,973✔
5991
  for (int32_t i = pInput->startRowIndex; i < pInput->numOfRows + pInput->startRowIndex; ++i) {
126,824,015✔
5992
    if (colDataIsNull_s(pInputCol, i)) {
248,770,426✔
5993
      continue;
400,266✔
5994
    }
5995
    numOfElems++;
123,984,947✔
5996

5997
    char*   data = colDataGetData(pInputCol, i);
123,984,947!
5998
    int32_t code = doModeAdd(pInfo, i, pCtx, data);
123,984,947✔
5999
    if (code != TSDB_CODE_SUCCESS) {
123,985,346✔
6000
      modeFunctionCleanup(pInfo);
570✔
6001
      return code;
×
6002
    }
6003
  }
6004

6005
  if (numOfElems == 0 && pCtx->subsidiaries.num > 0 && !pInfo->nullTupleSaved) {
2,438,802!
6006
    int32_t code = saveTupleData(pCtx, pInput->startRowIndex, pCtx->pSrcBlock, &pInfo->nullTuplePos);
30✔
6007
    if (code != TSDB_CODE_SUCCESS) {
30!
6008
      modeFunctionCleanup(pInfo);
×
6009
      return code;
×
6010
    }
6011
    pInfo->nullTupleSaved = true;
30✔
6012
  }
6013

6014
  SET_VAL(pResInfo, numOfElems, 1);
2,438,802✔
6015

6016
  return TSDB_CODE_SUCCESS;
2,438,802✔
6017
}
6018

6019
int32_t modeFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
25,675✔
6020
  int32_t              code = TSDB_CODE_SUCCESS;
25,675✔
6021
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
25,675✔
6022
  SModeInfo*           pInfo = GET_ROWCELL_INTERBUF(pResInfo);
25,675✔
6023
  int32_t              slotId = pCtx->pExpr->base.resSchema.slotId;
25,675✔
6024
  SColumnInfoData*     pCol = taosArrayGet(pBlock->pDataBlock, slotId);
25,675✔
6025
  int32_t              currentRow = pBlock->info.rows;
25,675✔
6026
  if (NULL == pCol) {
25,675!
6027
    modeFunctionCleanup(pInfo);
×
6028
    return TSDB_CODE_OUT_OF_RANGE;
×
6029
  }
6030

6031
  STuplePos resDataPos, resTuplePos;
6032
  int32_t   maxCount = 0;
25,675✔
6033

6034
  void* pIter = taosHashIterate(pInfo->pHash, NULL);
25,675✔
6035
  while (pIter != NULL) {
49,227,414✔
6036
    SModeItem* pItem = (SModeItem*)pIter;
49,201,739✔
6037
    if (pItem->count >= maxCount) {
49,201,739✔
6038
      maxCount = pItem->count;
37,152,814✔
6039
      resDataPos = pItem->dataPos;
37,152,814✔
6040
      resTuplePos = pItem->tuplePos;
37,152,814✔
6041
    }
6042

6043
    pIter = taosHashIterate(pInfo->pHash, pIter);
49,201,739✔
6044
  }
6045

6046
  if (maxCount != 0) {
25,675✔
6047
    char* pData = NULL;
23,569✔
6048
    code = loadTupleData(pCtx, &resDataPos, &pData);
23,569✔
6049
    if (pData == NULL || TSDB_CODE_SUCCESS != code) {
23,569!
6050
      code = terrno = TSDB_CODE_NOT_FOUND;
×
6051
      qError("Load tuple data failed since %s, groupId:%" PRIu64 ", ts:%" PRId64, terrstr(),
×
6052
             resDataPos.streamTupleKey.groupId, resDataPos.streamTupleKey.ts);
6053
      modeFunctionCleanup(pInfo);
×
6054
      return code;
×
6055
    }
6056

6057
    code = colDataSetVal(pCol, currentRow, pData, false);
23,569✔
6058
    if (TSDB_CODE_SUCCESS != code) {
23,569!
6059
      modeFunctionCleanup(pInfo);
×
6060
      return code;
×
6061
    }
6062
    code = setSelectivityValue(pCtx, pBlock, &resTuplePos, currentRow);
23,569✔
6063
  } else {
6064
    colDataSetNULL(pCol, currentRow);
2,106✔
6065
    code = setSelectivityValue(pCtx, pBlock, &pInfo->nullTuplePos, currentRow);
2,106✔
6066
  }
6067

6068
  modeFunctionCleanup(pInfo);
25,675✔
6069

6070
  return code;
25,675✔
6071
}
6072

6073
bool getTwaFuncEnv(struct SFunctionNode* pFunc, SFuncExecEnv* pEnv) {
78,443✔
6074
  pEnv->calcMemSize = sizeof(STwaInfo);
78,443✔
6075
  return true;
78,443✔
6076
}
6077

6078
int32_t twaFunctionSetup(SqlFunctionCtx* pCtx, SResultRowEntryInfo* pResultInfo) {
9,982,163✔
6079
  if (pResultInfo->initialized) {
9,982,163!
6080
    return TSDB_CODE_SUCCESS;
×
6081
  }
6082
  if (TSDB_CODE_SUCCESS != functionSetup(pCtx, pResultInfo)) {
9,982,163!
6083
    return TSDB_CODE_FUNC_SETUP_ERROR;
×
6084
  }
6085

6086
  STwaInfo* pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
9,982,193✔
6087
  pInfo->numOfElems = 0;
9,982,193✔
6088
  pInfo->p.key = INT64_MIN;
9,982,193✔
6089
  pInfo->win = TSWINDOW_INITIALIZER;
9,982,193✔
6090
  return TSDB_CODE_SUCCESS;
9,982,193✔
6091
}
6092

6093
static double twa_get_area(SPoint1 s, SPoint1 e) {
26,947,843✔
6094
  if (e.key == INT64_MAX || s.key == INT64_MIN) {
26,947,843!
6095
    return 0;
×
6096
  }
6097

6098
  if ((s.val >= 0 && e.val >= 0) || (s.val <= 0 && e.val <= 0)) {
26,948,098✔
6099
    return (s.val + e.val) * (e.key - s.key) / 2;
15,480,052✔
6100
  }
6101

6102
  double x = (s.key * e.val - e.key * s.val) / (e.val - s.val);
11,468,046✔
6103
  double val = (s.val * (x - s.key) + e.val * (e.key - x)) / 2;
11,468,046✔
6104
  return val;
11,468,046✔
6105
}
6106

6107
int32_t twaFunction(SqlFunctionCtx* pCtx) {
9,997,373✔
6108
  int32_t               code = TSDB_CODE_SUCCESS;
9,997,373✔
6109
  SInputColumnInfoData* pInput = &pCtx->input;
9,997,373✔
6110
  SColumnInfoData*      pInputCol = pInput->pData[0];
9,997,373✔
6111

6112
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
9,997,373✔
6113
  STwaInfo*            pInfo = GET_ROWCELL_INTERBUF(pResInfo);
9,997,373✔
6114
  SPoint1*             last = &pInfo->p;
9,997,373✔
6115

6116
  if (IS_NULL_TYPE(pInputCol->info.type)) {
9,997,373!
6117
    pInfo->numOfElems = 0;
×
6118
    goto _twa_over;
×
6119
  }
6120

6121
  funcInputUpdate(pCtx);
9,997,373✔
6122
  SFuncInputRow row = {0};
9,997,457✔
6123
  bool          result = false;
9,997,457✔
6124
  if (pCtx->start.key != INT64_MIN && last->key == INT64_MIN) {
9,997,457!
6125
    while (1) {
6126
      code = funcInputGetNextRow(pCtx, &row, &result);
3,122,961✔
6127
      if (TSDB_CODE_SUCCESS != code) {
3,122,935!
6128
        return code;
×
6129
      }
6130
      if (!result) {
3,122,935✔
6131
        break;
2✔
6132
      }
6133
      if (row.isDataNull) {
3,122,933✔
6134
        continue;
2✔
6135
      }
6136

6137
      last->key = row.ts;
3,122,931✔
6138

6139
      GET_TYPED_DATA(last->val, double, pInputCol->info.type, row.pData);
3,122,931!
6140

6141
      pInfo->dOutput += twa_get_area(pCtx->start, *last);
3,122,931✔
6142
      pInfo->win.skey = pCtx->start.key;
3,122,884✔
6143
      pInfo->numOfElems++;
3,122,884✔
6144
      break;
3,122,884✔
6145
    }
6146
  } else if (pInfo->p.key == INT64_MIN) {
6,874,498✔
6147
    while (1) {
6148
      code = funcInputGetNextRow(pCtx, &row, &result);
6,984,614✔
6149
      if (TSDB_CODE_SUCCESS != code) {
6,984,392!
6150
        return code;
×
6151
      }
6152
      if (!result) {
6,984,392✔
6153
        break;
11,679✔
6154
      }
6155
      if (row.isDataNull) {
6,972,713✔
6156
        continue;
125,080✔
6157
      }
6158

6159
      last->key = row.ts;
6,847,633✔
6160

6161
      GET_TYPED_DATA(last->val, double, pInputCol->info.type, row.pData);
6,847,633!
6162

6163
      pInfo->win.skey = last->key;
6,847,633✔
6164
      pInfo->numOfElems++;
6,847,633✔
6165
      break;
6,847,633✔
6166
    }
6167
  }
6168

6169
  SPoint1 st = {0};
9,997,162✔
6170

6171
  // calculate the value of
6172
  while (1) {
6173
    code = funcInputGetNextRow(pCtx, &row, &result);
30,654,459✔
6174
    if (TSDB_CODE_SUCCESS != code) {
30,654,336!
6175
      return code;
×
6176
    }
6177
    if (!result) {
30,654,336✔
6178
      break;
9,997,525✔
6179
    }
6180
    if (row.isDataNull) {
20,656,811✔
6181
      continue;
630✔
6182
    }
6183
    pInfo->numOfElems++;
20,656,181✔
6184
    switch (pInputCol->info.type) {
20,656,181!
6185
      case TSDB_DATA_TYPE_TINYINT: {
67,293✔
6186
        INIT_INTP_POINT(st, row.ts, *(int8_t*)row.pData);
67,293✔
6187
        break;
67,293✔
6188
      }
6189
      case TSDB_DATA_TYPE_SMALLINT: {
71,591✔
6190
        INIT_INTP_POINT(st, row.ts, *(int16_t*)row.pData);
71,591✔
6191
        break;
71,591✔
6192
      }
6193
      case TSDB_DATA_TYPE_INT: {
2,479,469✔
6194
        INIT_INTP_POINT(st, row.ts, *(int32_t*)row.pData);
2,479,469✔
6195
        break;
2,479,469✔
6196
      }
6197
      case TSDB_DATA_TYPE_BIGINT: {
895,843✔
6198
        INIT_INTP_POINT(st, row.ts, *(int64_t*)row.pData);
895,843✔
6199
        break;
895,843✔
6200
      }
6201
      case TSDB_DATA_TYPE_FLOAT: {
16,618,588✔
6202
        INIT_INTP_POINT(st, row.ts, *(float_t*)row.pData);
16,618,588✔
6203
        break;
16,618,588✔
6204
      }
6205
      case TSDB_DATA_TYPE_DOUBLE: {
337,539✔
6206
        INIT_INTP_POINT(st, row.ts, *(double*)row.pData);
337,539✔
6207
        break;
337,539✔
6208
      }
6209
      case TSDB_DATA_TYPE_UTINYINT: {
48,625✔
6210
        INIT_INTP_POINT(st, row.ts, *(uint8_t*)row.pData);
48,625✔
6211
        break;
48,625✔
6212
      }
6213
      case TSDB_DATA_TYPE_USMALLINT: {
48,547✔
6214
        INIT_INTP_POINT(st, row.ts, *(uint16_t*)row.pData);
48,547✔
6215
        break;
48,547✔
6216
      }
6217
      case TSDB_DATA_TYPE_UINT: {
50,414✔
6218
        INIT_INTP_POINT(st, row.ts, *(uint32_t*)row.pData);
50,414✔
6219
        break;
50,414✔
6220
      }
6221
      case TSDB_DATA_TYPE_UBIGINT: {
38,778✔
6222
        INIT_INTP_POINT(st, row.ts, *(uint64_t*)row.pData);
38,778✔
6223
        break;
38,778✔
6224
      }
6225
      default: {
×
6226
        return TSDB_CODE_FUNC_FUNTION_PARA_TYPE;
×
6227
      }
6228
    }
6229
    if (pInfo->p.key == st.key) {
20,656,687!
6230
      return TSDB_CODE_FUNC_DUP_TIMESTAMP;
×
6231
    }
6232

6233
    pInfo->dOutput += twa_get_area(pInfo->p, st);
20,656,687✔
6234
    pInfo->p = st;
20,656,667✔
6235
  }
6236

6237
  // the last interpolated time window value
6238
  if (pCtx->end.key != INT64_MIN) {
9,997,525✔
6239
    pInfo->dOutput += twa_get_area(pInfo->p, pCtx->end);
3,169,612✔
6240
    pInfo->p = pCtx->end;
3,169,598✔
6241
    pInfo->numOfElems += 1;
3,169,598✔
6242
  }
6243

6244
  pInfo->win.ekey = pInfo->p.key;
9,997,511✔
6245

6246
_twa_over:
9,997,511✔
6247
  SET_VAL(pResInfo, 1, 1);
9,997,511✔
6248
  return TSDB_CODE_SUCCESS;
9,997,511✔
6249
}
6250

6251
/*
6252
 * To copy the input to interResBuf to avoid the input buffer space be over writen
6253
 * by next input data. The TWA function only applies to each table, so no merge procedure
6254
 * is required, we simply copy to the resut ot interResBuffer.
6255
 */
6256
// void twa_function_copy(SQLFunctionCtx *pCtx) {
6257
//   SResultRowEntryInfo *pResInfo = GET_RES_INFO(pCtx);
6258
//
6259
//   memcpy(GET_ROWCELL_INTERBUF(pResInfo), pCtx->pInput, (size_t)pCtx->inputBytes);
6260
//   pResInfo->hasResult = ((STwaInfo *)pCtx->pInput)->hasResult;
6261
// }
6262

6263
int32_t twaFinalize(struct SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
9,978,128✔
6264
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
9,978,128✔
6265

6266
  STwaInfo* pInfo = (STwaInfo*)GET_ROWCELL_INTERBUF(pResInfo);
9,978,128✔
6267
  if (pInfo->numOfElems == 0) {
9,978,128✔
6268
    pResInfo->numOfRes = 0;
11,591✔
6269
  } else {
6270
    if (pInfo->win.ekey == pInfo->win.skey) {
9,966,537✔
6271
      pInfo->dTwaRes = pInfo->p.val;
5,364,522✔
6272
    } else if (pInfo->win.ekey == INT64_MAX || pInfo->win.skey == INT64_MIN) {  // no data in timewindow
4,602,015!
6273
      pInfo->dTwaRes = 0;
×
6274
    } else {
6275
      pInfo->dTwaRes = pInfo->dOutput / (pInfo->win.ekey - pInfo->win.skey);
4,602,249✔
6276
    }
6277

6278
    pResInfo->numOfRes = 1;
9,966,537✔
6279
  }
6280

6281
  return functionFinalize(pCtx, pBlock);
9,978,128✔
6282
}
6283

6284
int32_t blockDistSetup(SqlFunctionCtx* pCtx, SResultRowEntryInfo* pResultInfo) {
1,628✔
6285
  if (pResultInfo->initialized) {
1,628!
6286
    return TSDB_CODE_SUCCESS;
×
6287
  }
6288
  if (TSDB_CODE_SUCCESS != functionSetup(pCtx, pResultInfo)) {
1,628!
6289
    return TSDB_CODE_FUNC_SETUP_ERROR;
×
6290
  }
6291

6292
  STableBlockDistInfo* pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
1,628✔
6293
  pInfo->minRows = INT32_MAX;
1,628✔
6294
  return TSDB_CODE_SUCCESS;
1,628✔
6295
}
6296

6297
int32_t blockDistFunction(SqlFunctionCtx* pCtx) {
3,253✔
6298
  const int32_t BLOCK_DIST_RESULT_ROWS = 25;
3,253✔
6299

6300
  SInputColumnInfoData* pInput = &pCtx->input;
3,253✔
6301
  SColumnInfoData*      pInputCol = pInput->pData[0];
3,253✔
6302
  SResultRowEntryInfo*  pResInfo = GET_RES_INFO(pCtx);
3,253✔
6303
  STableBlockDistInfo*  pDistInfo = GET_ROWCELL_INTERBUF(pResInfo);
3,253✔
6304

6305
  STableBlockDistInfo p1 = {0};
3,253✔
6306
  if (tDeserializeBlockDistInfo(varDataVal(pInputCol->pData), varDataLen(pInputCol->pData), &p1) < 0) {
3,253!
6307
    qError("failed to deserialize block dist info");
×
6308
    return TSDB_CODE_FAILED;
×
6309
  }
6310

6311
  pDistInfo->numOfBlocks += p1.numOfBlocks;
3,253✔
6312
  pDistInfo->numOfTables += p1.numOfTables;
3,253✔
6313
  pDistInfo->numOfInmemRows += p1.numOfInmemRows;
3,253✔
6314
  pDistInfo->numOfSttRows += p1.numOfSttRows;
3,253✔
6315
  pDistInfo->totalSize += p1.totalSize;
3,253✔
6316
  pDistInfo->totalRows += p1.totalRows;
3,253✔
6317
  pDistInfo->numOfFiles += p1.numOfFiles;
3,253✔
6318

6319
  pDistInfo->defMinRows = p1.defMinRows;
3,253✔
6320
  pDistInfo->defMaxRows = p1.defMaxRows;
3,253✔
6321
  pDistInfo->rowSize = p1.rowSize;
3,253✔
6322

6323
  if (pDistInfo->minRows > p1.minRows) {
3,253✔
6324
    pDistInfo->minRows = p1.minRows;
2✔
6325
  }
6326
  if (pDistInfo->maxRows < p1.maxRows) {
3,253✔
6327
    pDistInfo->maxRows = p1.maxRows;
2✔
6328
  }
6329
  pDistInfo->numOfVgroups += (p1.numOfTables != 0 ? 1 : 0);
3,253✔
6330
  for (int32_t i = 0; i < tListLen(pDistInfo->blockRowsHisto); ++i) {
68,313✔
6331
    pDistInfo->blockRowsHisto[i] += p1.blockRowsHisto[i];
65,060✔
6332
  }
6333

6334
  pResInfo->numOfRes = BLOCK_DIST_RESULT_ROWS;  // default output rows
3,253✔
6335
  return TSDB_CODE_SUCCESS;
3,253✔
6336
}
6337

6338
int32_t tSerializeBlockDistInfo(void* buf, int32_t bufLen, const STableBlockDistInfo* pInfo) {
6,500✔
6339
  SEncoder encoder = {0};
6,500✔
6340
  int32_t  code = 0;
6,500✔
6341
  int32_t  lino;
6342
  int32_t  tlen;
6343
  tEncoderInit(&encoder, buf, bufLen);
6,500✔
6344

6345
  TAOS_CHECK_EXIT(tStartEncode(&encoder));
6,503!
6346
  TAOS_CHECK_EXIT(tEncodeU32(&encoder, pInfo->rowSize));
13,002!
6347

6348
  TAOS_CHECK_EXIT(tEncodeU16(&encoder, pInfo->numOfFiles));
13,002!
6349
  TAOS_CHECK_EXIT(tEncodeU32(&encoder, pInfo->numOfBlocks));
13,002!
6350
  TAOS_CHECK_EXIT(tEncodeU32(&encoder, pInfo->numOfTables));
13,002!
6351

6352
  TAOS_CHECK_EXIT(tEncodeU64(&encoder, pInfo->totalSize));
13,002!
6353
  TAOS_CHECK_EXIT(tEncodeU64(&encoder, pInfo->totalRows));
13,002!
6354
  TAOS_CHECK_EXIT(tEncodeI32(&encoder, pInfo->maxRows));
13,002!
6355
  TAOS_CHECK_EXIT(tEncodeI32(&encoder, pInfo->minRows));
13,002!
6356
  TAOS_CHECK_EXIT(tEncodeI32(&encoder, pInfo->defMaxRows));
13,002!
6357
  TAOS_CHECK_EXIT(tEncodeI32(&encoder, pInfo->defMinRows));
13,002!
6358
  TAOS_CHECK_EXIT(tEncodeU32(&encoder, pInfo->numOfInmemRows));
13,002!
6359
  TAOS_CHECK_EXIT(tEncodeU32(&encoder, pInfo->numOfSttRows));
13,002!
6360
  TAOS_CHECK_EXIT(tEncodeU32(&encoder, pInfo->numOfVgroups));
13,002!
6361

6362
  for (int32_t i = 0; i < tListLen(pInfo->blockRowsHisto); ++i) {
136,398✔
6363
    TAOS_CHECK_EXIT(tEncodeI32(&encoder, pInfo->blockRowsHisto[i]));
259,794!
6364
  }
6365

6366
  tEndEncode(&encoder);
6,501✔
6367

6368
_exit:
6,505✔
6369
  if (code) {
6,505!
6370
    tlen = code;
×
6371
  } else {
6372
    tlen = encoder.pos;
6,505✔
6373
  }
6374
  tEncoderClear(&encoder);
6,505✔
6375
  return tlen;
6,501✔
6376
}
6377

6378
int32_t tDeserializeBlockDistInfo(void* buf, int32_t bufLen, STableBlockDistInfo* pInfo) {
3,253✔
6379
  SDecoder decoder = {0};
3,253✔
6380
  int32_t  code = 0;
3,253✔
6381
  int32_t  lino;
6382
  tDecoderInit(&decoder, buf, bufLen);
3,253✔
6383

6384
  TAOS_CHECK_EXIT(tStartDecode(&decoder));
3,253!
6385
  TAOS_CHECK_EXIT(tDecodeU32(&decoder, &pInfo->rowSize));
6,506!
6386

6387
  TAOS_CHECK_EXIT(tDecodeU16(&decoder, &pInfo->numOfFiles));
6,506!
6388
  TAOS_CHECK_EXIT(tDecodeU32(&decoder, &pInfo->numOfBlocks));
6,506!
6389
  TAOS_CHECK_EXIT(tDecodeU32(&decoder, &pInfo->numOfTables));
6,506!
6390

6391
  TAOS_CHECK_EXIT(tDecodeU64(&decoder, &pInfo->totalSize));
6,506!
6392
  TAOS_CHECK_EXIT(tDecodeU64(&decoder, &pInfo->totalRows));
6,506!
6393
  TAOS_CHECK_EXIT(tDecodeI32(&decoder, &pInfo->maxRows));
6,506!
6394
  TAOS_CHECK_EXIT(tDecodeI32(&decoder, &pInfo->minRows));
6,506!
6395
  TAOS_CHECK_EXIT(tDecodeI32(&decoder, &pInfo->defMaxRows));
6,506!
6396
  TAOS_CHECK_EXIT(tDecodeI32(&decoder, &pInfo->defMinRows));
6,506!
6397
  TAOS_CHECK_EXIT(tDecodeU32(&decoder, &pInfo->numOfInmemRows));
6,506!
6398
  TAOS_CHECK_EXIT(tDecodeU32(&decoder, &pInfo->numOfSttRows));
6,506!
6399
  TAOS_CHECK_EXIT(tDecodeU32(&decoder, &pInfo->numOfVgroups));
6,506!
6400

6401
  for (int32_t i = 0; i < tListLen(pInfo->blockRowsHisto); ++i) {
68,313✔
6402
    TAOS_CHECK_EXIT(tDecodeI32(&decoder, &pInfo->blockRowsHisto[i]));
130,120!
6403
  }
6404

6405
_exit:
3,253✔
6406
  tDecoderClear(&decoder);
3,253✔
6407
  return code;
3,253✔
6408
}
6409

6410
int32_t blockDistFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
1,628✔
6411
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
1,628✔
6412
  STableBlockDistInfo* pData = GET_ROWCELL_INTERBUF(pResInfo);
1,628✔
6413

6414
  SColumnInfoData* pColInfo = taosArrayGet(pBlock->pDataBlock, 0);
1,628✔
6415
  if (NULL == pColInfo) {
1,628!
6416
    return TSDB_CODE_OUT_OF_RANGE;
×
6417
  }
6418

6419
  if (pData->totalRows == 0) {
1,628✔
6420
    pData->minRows = 0;
1,626✔
6421
  }
6422

6423
  int32_t row = 0;
1,628✔
6424
  char    st[256] = {0};
1,628✔
6425
  double  averageSize = 0;
1,628✔
6426
  if (pData->numOfBlocks != 0) {
1,628✔
6427
    averageSize = ((double)pData->totalSize) / pData->numOfBlocks;
2✔
6428
  }
6429
  uint64_t totalRawSize = pData->totalRows * pData->rowSize;
1,628✔
6430
  double   compRatio = 0;
1,628✔
6431
  if (totalRawSize != 0) {
1,628✔
6432
    compRatio = pData->totalSize * 100 / (double)totalRawSize;
2✔
6433
  }
6434

6435
  int32_t len = tsnprintf(varDataVal(st), sizeof(st) - VARSTR_HEADER_SIZE,
3,256✔
6436
                          "Total_Blocks=[%d] Total_Size=[%.2f KiB] Average_size=[%.2f KiB] Compression_Ratio=[%.2f %c]",
6437
                          pData->numOfBlocks, pData->totalSize / 1024.0, averageSize / 1024.0, compRatio, '%');
1,628✔
6438

6439
  varDataSetLen(st, len);
1,628✔
6440
  int32_t code = colDataSetVal(pColInfo, row++, st, false);
1,628✔
6441
  if (TSDB_CODE_SUCCESS != code) {
1,628!
6442
    return code;
×
6443
  }
6444

6445
  int64_t avgRows = 0;
1,628✔
6446
  if (pData->numOfBlocks > 0) {
1,628✔
6447
    avgRows = pData->totalRows / pData->numOfBlocks;
2✔
6448
  }
6449

6450
  len = tsnprintf(varDataVal(st), sizeof(st) - VARSTR_HEADER_SIZE,
1,628✔
6451
                  "Block_Rows=[%" PRId64 "] MinRows=[%d] MaxRows=[%d] AvgRows=[%" PRId64 "]", pData->totalRows,
6452
                  pData->minRows, pData->maxRows, avgRows);
6453
  varDataSetLen(st, len);
1,628✔
6454
  code = colDataSetVal(pColInfo, row++, st, false);
1,628✔
6455
  if (TSDB_CODE_SUCCESS != code) {
1,628!
6456
    return code;
×
6457
  }
6458

6459
  len = tsnprintf(varDataVal(st), sizeof(st) - VARSTR_HEADER_SIZE, "Inmem_Rows=[%u] Stt_Rows=[%u] ",
1,628✔
6460
                  pData->numOfInmemRows, pData->numOfSttRows);
6461
  varDataSetLen(st, len);
1,628✔
6462
  code = colDataSetVal(pColInfo, row++, st, false);
1,628✔
6463
  if (TSDB_CODE_SUCCESS != code) {
1,628!
6464
    return code;
×
6465
  }
6466

6467
  len = tsnprintf(varDataVal(st), sizeof(st) - VARSTR_HEADER_SIZE,
3,256✔
6468
                  "Total_Tables=[%d] Total_Filesets=[%d] Total_Vgroups=[%d]", pData->numOfTables, pData->numOfFiles,
1,628✔
6469
                  pData->numOfVgroups);
6470

6471
  varDataSetLen(st, len);
1,628✔
6472
  code = colDataSetVal(pColInfo, row++, st, false);
1,628✔
6473
  if (TSDB_CODE_SUCCESS != code) {
1,628!
6474
    return code;
×
6475
  }
6476

6477
  len = tsnprintf(varDataVal(st), sizeof(st) - VARSTR_HEADER_SIZE,
1,628✔
6478
                  "--------------------------------------------------------------------------------");
6479
  varDataSetLen(st, len);
1,628✔
6480
  code = colDataSetVal(pColInfo, row++, st, false);
1,628✔
6481
  if (TSDB_CODE_SUCCESS != code) {
1,628!
6482
    return code;
×
6483
  }
6484

6485
  int32_t maxVal = 0;
1,628✔
6486
  int32_t minVal = INT32_MAX;
1,628✔
6487
  for (int32_t i = 0; i < tListLen(pData->blockRowsHisto); ++i) {
34,188✔
6488
    if (maxVal < pData->blockRowsHisto[i]) {
32,560✔
6489
      maxVal = pData->blockRowsHisto[i];
3✔
6490
    }
6491

6492
    if (minVal > pData->blockRowsHisto[i]) {
32,560✔
6493
      minVal = pData->blockRowsHisto[i];
1,629✔
6494
    }
6495
  }
6496

6497
  // maximum number of step is 80
6498
  double factor = pData->numOfBlocks / 80.0;
1,628✔
6499

6500
  int32_t numOfBuckets = sizeof(pData->blockRowsHisto) / sizeof(pData->blockRowsHisto[0]);
1,628✔
6501
  int32_t bucketRange = ceil(((double)(pData->defMaxRows - pData->defMinRows)) / numOfBuckets);
1,628✔
6502

6503
  for (int32_t i = 0; i < tListLen(pData->blockRowsHisto); ++i) {
34,188✔
6504
    len =
32,560✔
6505
        tsnprintf(varDataVal(st), sizeof(st) - VARSTR_HEADER_SIZE, "%04d |", pData->defMinRows + bucketRange * (i + 1));
32,560✔
6506

6507
    int32_t num = 0;
32,560✔
6508
    if (pData->blockRowsHisto[i] > 0) {
32,560✔
6509
      num = (pData->blockRowsHisto[i]) / factor;
3✔
6510
    }
6511

6512
    for (int32_t j = 0; j < num; ++j) {
32,719✔
6513
      int32_t x = tsnprintf(varDataVal(st) + len, sizeof(st) - VARSTR_HEADER_SIZE - len, "%c", '|');
159✔
6514
      len += x;
159✔
6515
    }
6516

6517
    if (pData->blockRowsHisto[i] > 0) {
32,560✔
6518
      double v = pData->blockRowsHisto[i] * 100.0 / pData->numOfBlocks;
3✔
6519
      len += tsnprintf(varDataVal(st) + len, sizeof(st) - VARSTR_HEADER_SIZE - len, "  %d (%.2f%c)",
3✔
6520
                       pData->blockRowsHisto[i], v, '%');
6521
    }
6522

6523
    varDataSetLen(st, len);
32,560✔
6524
    code = colDataSetVal(pColInfo, row++, st, false);
32,560✔
6525
    if (TSDB_CODE_SUCCESS != code) {
32,560!
6526
      return code;
×
6527
    }
6528
  }
6529

6530
  return TSDB_CODE_SUCCESS;
1,628✔
6531
}
6532
int32_t blockDBUsageSetup(SqlFunctionCtx* pCtx, SResultRowEntryInfo* pResultInfo) {
1✔
6533
  if (pResultInfo->initialized) {
1!
6534
    return TSDB_CODE_SUCCESS;
×
6535
  }
6536
  if (TSDB_CODE_SUCCESS != functionSetup(pCtx, pResultInfo)) {
1!
6537
    return TSDB_CODE_FUNC_SETUP_ERROR;
×
6538
  }
6539

6540
  SDBBlockUsageInfo* pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
1✔
6541
  return TSDB_CODE_SUCCESS;
1✔
6542
}
6543
int32_t blockDBUsageFunction(SqlFunctionCtx* pCtx) {
2✔
6544
  const int32_t BLOCK_DISK_USAGE_RESULT_ROWS = 2;
2✔
6545

6546
  SInputColumnInfoData* pInput = &pCtx->input;
2✔
6547
  SColumnInfoData*      pInputCol = pInput->pData[0];
2✔
6548
  SResultRowEntryInfo*  pResInfo = GET_RES_INFO(pCtx);
2✔
6549
  SDBBlockUsageInfo*    pDistInfo = GET_ROWCELL_INTERBUF(pResInfo);
2✔
6550

6551
  SDBBlockUsageInfo p1 = {0};
2✔
6552
  if (tDeserializeBlockDbUsage(varDataVal(pInputCol->pData), varDataLen(pInputCol->pData), &p1) < 0) {
2!
6553
    qError("failed to deserialize block dist info");
×
6554
    return TSDB_CODE_FAILED;
×
6555
  }
6556

6557
  pDistInfo->dataInDiskSize += p1.dataInDiskSize;
2✔
6558
  pDistInfo->walInDiskSize += p1.walInDiskSize;
2✔
6559
  pDistInfo->rawDataSize += p1.rawDataSize;
2✔
6560
  pResInfo->numOfRes = BLOCK_DISK_USAGE_RESULT_ROWS;  // default output rows
2✔
6561
  return TSDB_CODE_SUCCESS;
2✔
6562
}
6563

6564
int32_t tSerializeBlockDbUsage(void* buf, int32_t bufLen, const SDBBlockUsageInfo* pInfo) {
4✔
6565
  SEncoder encoder = {0};
4✔
6566
  int32_t  code = 0;
4✔
6567
  int32_t  lino;
6568
  int32_t  tlen;
6569
  tEncoderInit(&encoder, buf, bufLen);
4✔
6570

6571
  TAOS_CHECK_EXIT(tStartEncode(&encoder));
4!
6572

6573
  TAOS_CHECK_EXIT(tEncodeU64(&encoder, pInfo->dataInDiskSize));
8!
6574
  TAOS_CHECK_EXIT(tEncodeU64(&encoder, pInfo->walInDiskSize));
8!
6575
  TAOS_CHECK_EXIT(tEncodeU64(&encoder, pInfo->rawDataSize));
8!
6576

6577
  tEndEncode(&encoder);
4✔
6578

6579
_exit:
4✔
6580
  if (code) {
4!
6581
    tlen = code;
×
6582
  } else {
6583
    tlen = encoder.pos;
4✔
6584
  }
6585
  tEncoderClear(&encoder);
4✔
6586
  return tlen;
4✔
6587
}
6588
int32_t tDeserializeBlockDbUsage(void* buf, int32_t bufLen, SDBBlockUsageInfo* pInfo) {
2✔
6589
  SDecoder decoder = {0};
2✔
6590
  int32_t  code = 0;
2✔
6591
  int32_t  lino;
6592
  tDecoderInit(&decoder, buf, bufLen);
2✔
6593

6594
  TAOS_CHECK_EXIT(tStartDecode(&decoder));
2!
6595
  TAOS_CHECK_EXIT(tDecodeU64(&decoder, &pInfo->dataInDiskSize));
4!
6596
  TAOS_CHECK_EXIT(tDecodeU64(&decoder, &pInfo->walInDiskSize));
4!
6597
  TAOS_CHECK_EXIT(tDecodeU64(&decoder, &pInfo->rawDataSize));
4!
6598

6599
_exit:
2✔
6600
  tDecoderClear(&decoder);
2✔
6601
  return code;
2✔
6602
}
6603
int32_t blockDBUsageFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
1✔
6604
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
1✔
6605
  SDBBlockUsageInfo*   pData = GET_ROWCELL_INTERBUF(pResInfo);
1✔
6606

6607
  SColumnInfoData* pColInfo = taosArrayGet(pBlock->pDataBlock, 0);
1✔
6608
  if (NULL == pColInfo) {
1!
6609
    return TSDB_CODE_OUT_OF_RANGE;
×
6610
  }
6611
  int32_t len = 0;
1✔
6612
  int32_t row = 0;
1✔
6613
  char    st[256] = {0};
1✔
6614

6615
  uint64_t totalDiskSize = pData->dataInDiskSize;
1✔
6616
  uint64_t rawDataSize = pData->rawDataSize;
1✔
6617
  double   compressRadio = 0;
1✔
6618
  if (rawDataSize != 0) {
1!
6619
    compressRadio = totalDiskSize * 100 / (double)rawDataSize;
1✔
6620
    len = tsnprintf(varDataVal(st), sizeof(st) - VARSTR_HEADER_SIZE, "Compress_radio=[%.2f]", compressRadio);
1✔
6621
  } else {
6622
    len = tsnprintf(varDataVal(st), sizeof(st) - VARSTR_HEADER_SIZE, "Compress_radio=[NULL]");
×
6623
  }
6624

6625
  varDataSetLen(st, len);
1✔
6626
  int32_t code = colDataSetVal(pColInfo, row++, st, false);
1✔
6627
  if (TSDB_CODE_SUCCESS != code) {
1!
6628
    return code;
×
6629
  }
6630

6631
  len =
1✔
6632
      tsnprintf(varDataVal(st), sizeof(st) - VARSTR_HEADER_SIZE, "Disk_occupied=[%" PRId64 "k]", pData->dataInDiskSize);
1✔
6633
  varDataSetLen(st, len);
1✔
6634
  code = colDataSetVal(pColInfo, row++, st, false);
1✔
6635
  if (TSDB_CODE_SUCCESS != code) {
1!
6636
    return code;
×
6637
  }
6638
  return code;
1✔
6639
}
6640

6641
bool getDerivativeFuncEnv(struct SFunctionNode* pFunc, SFuncExecEnv* pEnv) {
30,668✔
6642
  pEnv->calcMemSize = sizeof(SDerivInfo);
30,668✔
6643
  return true;
30,668✔
6644
}
6645

6646
int32_t derivativeFuncSetup(SqlFunctionCtx* pCtx, SResultRowEntryInfo* pResInfo) {
84,451✔
6647
  if (pResInfo->initialized) {
84,451✔
6648
    return TSDB_CODE_SUCCESS;
53,642✔
6649
  }
6650
  if (TSDB_CODE_SUCCESS != functionSetup(pCtx, pResInfo)) {
30,809!
6651
    return TSDB_CODE_FUNC_SETUP_ERROR;
×
6652
  }
6653

6654
  SDerivInfo* pDerivInfo = GET_ROWCELL_INTERBUF(pResInfo);
30,809✔
6655

6656
  pDerivInfo->ignoreNegative = pCtx->param[2].param.i;
30,809✔
6657
  pDerivInfo->prevTs = -1;
30,809✔
6658
  pDerivInfo->tsWindow = pCtx->param[1].param.i;
30,809✔
6659
  pDerivInfo->valueSet = false;
30,809✔
6660
  return TSDB_CODE_SUCCESS;
30,809✔
6661
}
6662

6663
int32_t derivativeFunction(SqlFunctionCtx* pCtx) {
53,783✔
6664
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
53,783✔
6665
  SDerivInfo*          pDerivInfo = GET_ROWCELL_INTERBUF(pResInfo);
53,783✔
6666

6667
  SInputColumnInfoData* pInput = &pCtx->input;
53,783✔
6668
  SColumnInfoData*      pInputCol = pInput->pData[0];
53,783✔
6669

6670
  int32_t          numOfElems = 0;
53,783✔
6671
  SColumnInfoData* pOutput = (SColumnInfoData*)pCtx->pOutput;
53,783✔
6672
  SColumnInfoData* pTsOutput = pCtx->pTsOutput;
53,783✔
6673
  int32_t          code = TSDB_CODE_SUCCESS;
53,783✔
6674

6675
  funcInputUpdate(pCtx);
53,783✔
6676

6677
  double v = 0;
53,783✔
6678
  if (pCtx->order == TSDB_ORDER_ASC) {
53,783✔
6679
    SFuncInputRow row = {0};
50,397✔
6680
    bool          result = false;
50,397✔
6681
    while (1) {
2,747,046✔
6682
      code = funcInputGetNextRow(pCtx, &row, &result);
2,797,443✔
6683
      if (TSDB_CODE_SUCCESS != code) {
2,797,443!
6684
        return code;
×
6685
      }
6686
      if (!result) {
2,797,443✔
6687
        break;
50,397✔
6688
      }
6689
      if (row.isDataNull) {
2,747,046✔
6690
        continue;
47,917✔
6691
      }
6692

6693
      char* d = row.pData;
2,699,129✔
6694
      GET_TYPED_DATA(v, double, pInputCol->info.type, d);
2,699,129!
6695

6696
      int32_t pos = pCtx->offset + numOfElems;
2,699,129✔
6697
      if (!pDerivInfo->valueSet) {  // initial value is not set yet
2,699,129✔
6698
        pDerivInfo->valueSet = true;
26,974✔
6699
      } else {
6700
        if (row.ts == pDerivInfo->prevTs) {
2,672,155!
6701
          return TSDB_CODE_FUNC_DUP_TIMESTAMP;
×
6702
        }
6703
        double r = ((v - pDerivInfo->prevValue) * pDerivInfo->tsWindow) / (row.ts - pDerivInfo->prevTs);
2,672,155✔
6704
        if (pDerivInfo->ignoreNegative && r < 0) {
2,672,155✔
6705
        } else {
6706
          if (isinf(r) || isnan(r)) {
1,872,116!
6707
            colDataSetNULL(pOutput, pos);
×
6708
          } else {
6709
            code = colDataSetVal(pOutput, pos, (const char*)&r, false);
1,872,116✔
6710
            if (code != TSDB_CODE_SUCCESS) {
1,872,116!
6711
              return code;
×
6712
            }
6713
          }
6714

6715
          if (pTsOutput != NULL) {
1,872,116!
6716
            colDataSetInt64(pTsOutput, pos, &row.ts);
×
6717
          }
6718

6719
          // handle selectivity
6720
          if (pCtx->subsidiaries.num > 0) {
1,872,116✔
6721
            code = appendSelectivityCols(pCtx, row.block, row.rowIndex, pos);
1,235,617✔
6722
            if (code != TSDB_CODE_SUCCESS) {
1,235,617!
6723
              return code;
×
6724
            }
6725
          }
6726

6727
          numOfElems++;
1,872,116✔
6728
        }
6729
      }
6730

6731
      pDerivInfo->prevValue = v;
2,699,129✔
6732
      pDerivInfo->prevTs = row.ts;
2,699,129✔
6733
    }
6734
  } else {
6735
    SFuncInputRow row = {0};
3,386✔
6736
    bool          result = false;
3,386✔
6737
    while (1) {
334,152✔
6738
      code = funcInputGetNextRow(pCtx, &row, &result);
337,538✔
6739
      if (TSDB_CODE_SUCCESS != code) {
337,538!
6740
        return code;
×
6741
      }
6742
      if (!result) {
337,538✔
6743
        break;
3,386✔
6744
      }
6745
      if (row.isDataNull) {
334,152✔
6746
        continue;
98✔
6747
      }
6748

6749
      char* d = row.pData;
334,054✔
6750
      GET_TYPED_DATA(v, double, pInputCol->info.type, d);
334,054!
6751

6752
      int32_t pos = pCtx->offset + numOfElems;
334,054✔
6753
      if (!pDerivInfo->valueSet) {  // initial value is not set yet
334,054✔
6754
        pDerivInfo->valueSet = true;
3,357✔
6755
      } else {
6756
        if (row.ts == pDerivInfo->prevTs) {
330,697!
6757
          return TSDB_CODE_FUNC_DUP_TIMESTAMP;
×
6758
        }
6759
        double r = ((pDerivInfo->prevValue - v) * pDerivInfo->tsWindow) / (pDerivInfo->prevTs - row.ts);
330,697✔
6760
        if (pDerivInfo->ignoreNegative && r < 0) {
330,697✔
6761
        } else {
6762
          if (isinf(r) || isnan(r)) {
254,395!
6763
            colDataSetNULL(pOutput, pos);
×
6764
          } else {
6765
            code = colDataSetVal(pOutput, pos, (const char*)&r, false);
254,395✔
6766
            if (code != TSDB_CODE_SUCCESS) {
254,395!
6767
              return code;
×
6768
            }
6769
          }
6770

6771
          if (pTsOutput != NULL) {
254,395!
6772
            colDataSetInt64(pTsOutput, pos, &pDerivInfo->prevTs);
×
6773
          }
6774

6775
          // handle selectivity
6776
          if (pCtx->subsidiaries.num > 0) {
254,395✔
6777
            code = appendSelectivityCols(pCtx, row.block, row.rowIndex, pos);
76,494✔
6778
            if (code != TSDB_CODE_SUCCESS) {
76,494!
6779
              return code;
×
6780
            }
6781
          }
6782
          numOfElems++;
254,395✔
6783
        }
6784
      }
6785

6786
      pDerivInfo->prevValue = v;
334,054✔
6787
      pDerivInfo->prevTs = row.ts;
334,054✔
6788
    }
6789
  }
6790

6791
  pResInfo->numOfRes = numOfElems;
53,783✔
6792

6793
  return TSDB_CODE_SUCCESS;
53,783✔
6794
}
6795

6796
int32_t getIrateInfoSize(int32_t pkBytes) { return (int32_t)sizeof(SRateInfo) + 2 * pkBytes; }
1,879,820✔
6797

6798
bool getIrateFuncEnv(struct SFunctionNode* pFunc, SFuncExecEnv* pEnv) {
124,882✔
6799
  int32_t pkBytes = (pFunc->hasPk) ? pFunc->pkBytes : 0;
124,882✔
6800
  pEnv->calcMemSize = getIrateInfoSize(pkBytes);
124,882✔
6801
  return true;
125,151✔
6802
}
6803

6804
int32_t irateFuncSetup(SqlFunctionCtx* pCtx, SResultRowEntryInfo* pResInfo) {
8,481,994✔
6805
  if (pResInfo->initialized) {
8,481,994!
6806
    return TSDB_CODE_SUCCESS;
×
6807
  }
6808
  if (TSDB_CODE_SUCCESS != functionSetup(pCtx, pResInfo)) {
8,481,994!
6809
    return TSDB_CODE_FUNC_SETUP_ERROR;
×
6810
  }
6811

6812
  SRateInfo* pInfo = GET_ROWCELL_INTERBUF(pResInfo);
8,481,994✔
6813

6814
  pInfo->firstKey = INT64_MIN;
8,481,994✔
6815
  pInfo->lastKey = INT64_MIN;
8,481,994✔
6816
  pInfo->firstValue = (double)INT64_MIN;
8,481,994✔
6817
  pInfo->lastValue = (double)INT64_MIN;
8,481,994✔
6818

6819
  pInfo->hasResult = 0;
8,481,994✔
6820
  return TSDB_CODE_SUCCESS;
8,481,994✔
6821
}
6822

6823
static void doSaveRateInfo(SRateInfo* pRateInfo, bool isFirst, int64_t ts, char* pk, double v) {
25,942,429✔
6824
  if (isFirst) {
25,942,429✔
6825
    pRateInfo->firstValue = v;
9,617,068✔
6826
    pRateInfo->firstKey = ts;
9,617,068✔
6827
    if (pRateInfo->firstPk) {
9,617,068✔
6828
      int32_t pkBytes;
6829
      if (IS_VAR_DATA_TYPE(pRateInfo->pkType)) {
35!
6830
        if (pRateInfo->pkType == TSDB_DATA_TYPE_JSON) {
8!
6831
          pkBytes = getJsonValueLen(pk);
×
6832
        } else {
6833
          pkBytes = varDataTLen(pk);
8✔
6834
        }
6835
      } else {
6836
        pkBytes = pRateInfo->pkBytes;
27✔
6837
      }
6838
      (void)memcpy(pRateInfo->firstPk, pk, pkBytes);
35✔
6839
    }
6840
  } else {
6841
    pRateInfo->lastValue = v;
16,325,361✔
6842
    pRateInfo->lastKey = ts;
16,325,361✔
6843
    if (pRateInfo->lastPk) {
16,325,361✔
6844
      int32_t pkBytes;
6845
      if (IS_VAR_DATA_TYPE(pRateInfo->pkType)) {
52!
6846
        if (pRateInfo->pkType == TSDB_DATA_TYPE_JSON) {
12!
6847
          pkBytes = getJsonValueLen(pk);
×
6848
        } else {
6849
          pkBytes = varDataTLen(pk);
12✔
6850
        }
6851
      } else {
6852
        pkBytes = pRateInfo->pkBytes;
40✔
6853
      }
6854
      (void)memcpy(pRateInfo->lastPk, pk, pkBytes);
52✔
6855
    }
6856
  }
6857
}
25,942,429✔
6858

6859
static void initializeRateInfo(SqlFunctionCtx* pCtx, SRateInfo* pRateInfo, bool isMerge) {
10,237,393✔
6860
  if (pCtx->hasPrimaryKey) {
10,237,393✔
6861
    if (!isMerge) {
19✔
6862
      pRateInfo->pkType = pCtx->input.pPrimaryKey->info.type;
17✔
6863
      pRateInfo->pkBytes = pCtx->input.pPrimaryKey->info.bytes;
17✔
6864
      pRateInfo->firstPk = pRateInfo->pkData;
17✔
6865
      pRateInfo->lastPk = pRateInfo->pkData + pRateInfo->pkBytes;
17✔
6866
    } else {
6867
      pRateInfo->firstPk = pRateInfo->pkData;
2✔
6868
      pRateInfo->lastPk = pRateInfo->pkData + pRateInfo->pkBytes;
2✔
6869
    }
6870
  } else {
6871
    pRateInfo->firstPk = NULL;
10,237,374✔
6872
    pRateInfo->lastPk = NULL;
10,237,374✔
6873
  }
6874
}
10,237,393✔
6875

6876
int32_t irateFunction(SqlFunctionCtx* pCtx) {
6,728,285✔
6877
  int32_t              code = TSDB_CODE_SUCCESS;
6,728,285✔
6878
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
6,728,285✔
6879
  SRateInfo*           pRateInfo = GET_ROWCELL_INTERBUF(pResInfo);
6,728,285✔
6880

6881
  SInputColumnInfoData* pInput = &pCtx->input;
6,728,285✔
6882
  SColumnInfoData*      pInputCol = pInput->pData[0];
6,728,285✔
6883

6884
  SColumnInfoData* pOutput = (SColumnInfoData*)pCtx->pOutput;
6,728,285✔
6885

6886
  funcInputUpdate(pCtx);
6,728,285✔
6887

6888
  initializeRateInfo(pCtx, pRateInfo, false);
6,728,310✔
6889

6890
  int32_t       numOfElems = 0;
6,728,292✔
6891
  int32_t       type = pInputCol->info.type;
6,728,292✔
6892
  SFuncInputRow row = {0};
6,728,292✔
6893
  bool          result = false;
6,728,292✔
6894
  while (1) {
14,840,336✔
6895
    code = funcInputGetNextRow(pCtx, &row, &result);
21,568,628✔
6896
    if (TSDB_CODE_SUCCESS != code) {
21,567,605!
6897
      return code;
×
6898
    }
6899
    if (!result) {
21,567,605✔
6900
      break;
6,728,163✔
6901
    }
6902
    if (row.isDataNull) {
14,839,442✔
6903
      continue;
127,578✔
6904
    }
6905

6906
    char*  data = row.pData;
14,711,864✔
6907
    double v = 0;
14,711,864✔
6908
    GET_TYPED_DATA(v, double, type, data);
14,711,864!
6909

6910
    if (INT64_MIN == pRateInfo->lastKey) {
14,711,864✔
6911
      doSaveRateInfo(pRateInfo, false, row.ts, row.pPk, v);
6,709,723✔
6912
      pRateInfo->hasResult = 1;
6,709,703✔
6913
      continue;
6,709,703✔
6914
    }
6915

6916
    if (row.ts > pRateInfo->lastKey) {
8,002,141✔
6917
      if ((INT64_MIN == pRateInfo->firstKey) || pRateInfo->lastKey > pRateInfo->firstKey) {
7,861,997!
6918
        doSaveRateInfo(pRateInfo, true, pRateInfo->lastKey, pRateInfo->lastPk, pRateInfo->lastValue);
7,862,002✔
6919
      }
6920
      doSaveRateInfo(pRateInfo, false, row.ts, row.pPk, v);
7,862,033✔
6921
      continue;
7,861,973✔
6922
    } else if (row.ts == pRateInfo->lastKey) {
140,144!
6923
      return TSDB_CODE_FUNC_DUP_TIMESTAMP;
×
6924
    }
6925

6926
    if ((INT64_MIN == pRateInfo->firstKey) || row.ts > pRateInfo->firstKey) {
140,144!
6927
      doSaveRateInfo(pRateInfo, true, row.ts, row.pPk, v);
×
6928
    } else if (row.ts == pRateInfo->firstKey) {
141,073!
6929
      return TSDB_CODE_FUNC_DUP_TIMESTAMP;
×
6930
    }
6931
  }
6932

6933
  numOfElems++;
6,728,163✔
6934

6935
  SET_VAL(pResInfo, numOfElems, 1);
6,728,163!
6936
  return TSDB_CODE_SUCCESS;
6,728,163✔
6937
}
6938

6939
static double doCalcRate(const SRateInfo* pRateInfo, double tickPerSec) {
6,724,348✔
6940
  if ((INT64_MIN == pRateInfo->lastKey) || (INT64_MIN == pRateInfo->firstKey) ||
6,724,348✔
6941
      (pRateInfo->firstKey >= pRateInfo->lastKey)) {
604,059!
6942
    return 0.0;
6,120,289✔
6943
  }
6944

6945
  double diff = 0;
604,059✔
6946
  // If the previous value of the last is greater than the last value, only keep the last point instead of the delta
6947
  // value between two values.
6948
  diff = pRateInfo->lastValue;
604,059✔
6949
  if (diff >= pRateInfo->firstValue) {
604,059✔
6950
    diff -= pRateInfo->firstValue;
297,205✔
6951
  }
6952

6953
  int64_t duration = pRateInfo->lastKey - pRateInfo->firstKey;
604,059✔
6954
  if (duration == 0) {
604,059!
6955
    return 0;
×
6956
  }
6957

6958
  return (duration > 0) ? ((double)diff) / (duration / tickPerSec) : 0.0;
604,059!
6959
}
6960

6961
static void irateTransferInfoImpl(TSKEY inputKey, SRateInfo* pInput, SRateInfo* pOutput, bool isFirstKey) {
174✔
6962
  if (inputKey > pOutput->lastKey) {
174✔
6963
    doSaveRateInfo(pOutput, true, pOutput->lastKey, pOutput->lastPk, pOutput->lastValue);
124✔
6964
    if (isFirstKey) {
124✔
6965
      doSaveRateInfo(pOutput, false, pInput->firstKey, pInput->firstPk, pInput->firstValue);
58✔
6966
    } else {
6967
      doSaveRateInfo(pOutput, false, pInput->lastKey, pInput->lastPk, pInput->lastValue);
66✔
6968
    }
6969
  } else if ((inputKey < pOutput->lastKey) && (inputKey > pOutput->firstKey)) {
50!
6970
    if (isFirstKey) {
20✔
6971
      doSaveRateInfo(pOutput, true, pInput->firstKey, pInput->firstPk, pInput->firstValue);
10✔
6972
    } else {
6973
      doSaveRateInfo(pOutput, true, pInput->lastKey, pInput->lastPk, pInput->lastValue);
10✔
6974
    }
6975
  } else {
6976
    // inputKey < pOutput->firstKey
6977
  }
6978
}
174✔
6979

6980
static void irateCopyInfo(SRateInfo* pInput, SRateInfo* pOutput) {
1,754,471✔
6981
  doSaveRateInfo(pOutput, true, pInput->firstKey, pInput->firstPk, pInput->firstValue);
1,754,471✔
6982
  doSaveRateInfo(pOutput, false, pInput->lastKey, pInput->lastPk, pInput->lastValue);
1,754,471✔
6983
}
1,754,471✔
6984

6985
static int32_t irateTransferInfo(SRateInfo* pInput, SRateInfo* pOutput) {
1,754,558✔
6986
  if ((pInput->firstKey != INT64_MIN &&
1,754,558✔
6987
       (pInput->firstKey == pOutput->firstKey || pInput->firstKey == pOutput->lastKey)) ||
132,023!
6988
      (pInput->lastKey != INT64_MIN && (pInput->lastKey == pOutput->firstKey || pInput->lastKey == pOutput->lastKey))) {
1,754,558!
6989
    return TSDB_CODE_FUNC_DUP_TIMESTAMP;
×
6990
  }
6991

6992
  if (pOutput->hasResult == 0) {
1,754,558✔
6993
    irateCopyInfo(pInput, pOutput);
1,754,471✔
6994
    pOutput->hasResult = pInput->hasResult;
1,754,471✔
6995
    return TSDB_CODE_SUCCESS;
1,754,471✔
6996
  }
6997

6998
  if (pInput->firstKey != INT64_MIN) {
87!
6999
    irateTransferInfoImpl(pInput->firstKey, pInput, pOutput, true);
87✔
7000
  }
7001

7002
  if (pInput->lastKey != INT64_MIN) {
87!
7003
    irateTransferInfoImpl(pInput->lastKey, pInput, pOutput, false);
87✔
7004
  }
7005

7006
  pOutput->hasResult = pInput->hasResult;
87✔
7007
  return TSDB_CODE_SUCCESS;
87✔
7008
}
7009

7010
int32_t irateFunctionMerge(SqlFunctionCtx* pCtx) {
1,754,566✔
7011
  SInputColumnInfoData* pInput = &pCtx->input;
1,754,566✔
7012
  SColumnInfoData*      pCol = pInput->pData[0];
1,754,566✔
7013
  if (pCol->info.type != TSDB_DATA_TYPE_BINARY) {
1,754,566!
7014
    return TSDB_CODE_FUNC_FUNTION_PARA_TYPE;
×
7015
  }
7016

7017
  SRateInfo* pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
1,754,566✔
7018
  initializeRateInfo(pCtx, pInfo, true);
1,754,566✔
7019

7020
  int32_t start = pInput->startRowIndex;
1,754,566✔
7021
  for (int32_t i = start; i < start + pInput->numOfRows; ++i) {
3,509,132✔
7022
    char*      data = colDataGetData(pCol, i);
1,754,566!
7023
    SRateInfo* pInputInfo = (SRateInfo*)varDataVal(data);
1,754,566✔
7024
    initializeRateInfo(pCtx, pInfo, true);
1,754,566✔
7025
    if (pInputInfo->hasResult) {
1,754,566✔
7026
      int32_t code = irateTransferInfo(pInputInfo, pInfo);
1,754,558✔
7027
      if (code != TSDB_CODE_SUCCESS) {
1,754,558!
7028
        return code;
×
7029
      }
7030
    }
7031
  }
7032

7033
  if (pInfo->hasResult) {
1,754,566✔
7034
    GET_RES_INFO(pCtx)->numOfRes = 1;
1,754,558✔
7035
  }
7036

7037
  return TSDB_CODE_SUCCESS;
1,754,566✔
7038
}
7039

7040
int32_t iratePartialFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
1,754,566✔
7041
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
1,754,566✔
7042
  SRateInfo*           pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
1,754,566✔
7043
  int32_t              resultBytes = getIrateInfoSize(pInfo->pkBytes);
1,754,566✔
7044
  char*                res = taosMemoryCalloc(resultBytes + VARSTR_HEADER_SIZE, sizeof(char));
1,754,566!
7045

7046
  if (NULL == res) {
1,754,566!
7047
    return terrno;
×
7048
  }
7049
  (void)memcpy(varDataVal(res), pInfo, resultBytes);
1,754,566✔
7050
  varDataSetLen(res, resultBytes);
1,754,566✔
7051

7052
  int32_t          slotId = pCtx->pExpr->base.resSchema.slotId;
1,754,566✔
7053
  SColumnInfoData* pCol = taosArrayGet(pBlock->pDataBlock, slotId);
1,754,566✔
7054
  if (NULL == pCol) {
1,754,566!
7055
    taosMemoryFree(res);
×
7056
    return TSDB_CODE_OUT_OF_RANGE;
×
7057
  }
7058

7059
  int32_t code = colDataSetVal(pCol, pBlock->info.rows, res, false);
1,754,566✔
7060

7061
  taosMemoryFree(res);
1,754,566!
7062
  return code;
1,754,566✔
7063
}
7064

7065
int32_t irateFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
6,724,574✔
7066
  int32_t          slotId = pCtx->pExpr->base.resSchema.slotId;
6,724,574✔
7067
  SColumnInfoData* pCol = taosArrayGet(pBlock->pDataBlock, slotId);
6,724,574✔
7068
  if (NULL == pCol) {
6,724,347!
7069
    return TSDB_CODE_OUT_OF_RANGE;
×
7070
  }
7071

7072
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
6,724,347✔
7073
  pResInfo->isNullRes = (pResInfo->numOfRes == 0) ? 1 : 0;
6,724,347✔
7074

7075
  SRateInfo* pInfo = GET_ROWCELL_INTERBUF(pResInfo);
6,724,347✔
7076
  double     result = doCalcRate(pInfo, (double)TSDB_TICK_PER_SECOND(pCtx->param[1].param.i));
6,724,347!
7077
  int32_t    code = colDataSetVal(pCol, pBlock->info.rows, (const char*)&result, pResInfo->isNullRes);
6,724,351✔
7078

7079
  return code;
6,724,114✔
7080
}
7081

7082
int32_t groupConstValueFunction(SqlFunctionCtx* pCtx) {
94,211,779✔
7083
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
94,211,779✔
7084
  SGroupKeyInfo*       pInfo = GET_ROWCELL_INTERBUF(pResInfo);
94,211,779✔
7085

7086
  SInputColumnInfoData* pInput = &pCtx->input;
94,211,779✔
7087
  SColumnInfoData*      pInputCol = pInput->pData[0];
94,211,779✔
7088

7089
  int32_t startIndex = pInput->startRowIndex;
94,211,779✔
7090

7091
  // escape rest of data blocks to avoid first entry to be overwritten.
7092
  if (pInfo->hasResult) {
94,211,779✔
7093
    goto _group_value_over;
10,605,456✔
7094
  }
7095

7096
  if (pInputCol->pData == NULL || colDataIsNull_s(pInputCol, startIndex)) {
166,905,927✔
7097
    pInfo->isNull = true;
2,085,001✔
7098
    pInfo->hasResult = true;
2,085,001✔
7099
    goto _group_value_over;
2,085,001✔
7100
  }
7101

7102
  char* data = colDataGetData(pInputCol, startIndex);
81,521,322!
7103
  if (IS_VAR_DATA_TYPE(pInputCol->info.type)) {
81,521,322!
7104
    (void)memcpy(pInfo->data, data,
61,090,642✔
7105
                 (pInputCol->info.type == TSDB_DATA_TYPE_JSON) ? getJsonValueLen(data) : varDataTLen(data));
61,090,642✔
7106
  } else {
7107
    (void)memcpy(pInfo->data, data, pInputCol->info.bytes);
20,430,680✔
7108
  }
7109
  pInfo->hasResult = true;
81,521,322✔
7110

7111
_group_value_over:
94,211,779✔
7112

7113
  SET_VAL(pResInfo, 1, 1);
94,211,779✔
7114
  return TSDB_CODE_SUCCESS;
94,211,779✔
7115
}
7116

7117
int32_t groupKeyFunction(SqlFunctionCtx* pCtx) { return groupConstValueFunction(pCtx); }
94,207,002✔
7118

7119
int32_t groupConstValueFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
82,326,245✔
7120
  int32_t          slotId = pCtx->pExpr->base.resSchema.slotId;
82,326,245✔
7121
  int32_t          code = TSDB_CODE_SUCCESS;
82,326,245✔
7122
  SColumnInfoData* pCol = taosArrayGet(pBlock->pDataBlock, slotId);
82,326,245✔
7123
  if (NULL == pCol) {
82,254,901!
7124
    return TSDB_CODE_OUT_OF_RANGE;
×
7125
  }
7126

7127
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
82,254,901✔
7128

7129
  SGroupKeyInfo* pInfo = GET_ROWCELL_INTERBUF(pResInfo);
82,254,901✔
7130

7131
  if (pInfo->hasResult) {
82,254,901!
7132
    int32_t currentRow = pBlock->info.rows;
82,279,924✔
7133
    for (; currentRow < pBlock->info.rows + pResInfo->numOfRes; ++currentRow) {
165,533,170✔
7134
      code = colDataSetVal(pCol, currentRow, pInfo->data, pInfo->isNull ? true : false);
82,300,218✔
7135
      if (TSDB_CODE_SUCCESS != code) {
83,253,246!
7136
        return code;
×
7137
      }
7138
    }
7139
  } else {
7140
    pResInfo->numOfRes = 0;
×
7141
  }
7142

7143
  return code;
83,207,929✔
7144
}
7145

7146
int32_t groupKeyFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) { return groupConstValueFinalize(pCtx, pBlock); }
82,347,828✔
7147

7148
int32_t groupKeyCombine(SqlFunctionCtx* pDestCtx, SqlFunctionCtx* pSourceCtx) {
×
7149
  SResultRowEntryInfo* pDResInfo = GET_RES_INFO(pDestCtx);
×
7150
  SGroupKeyInfo*       pDBuf = GET_ROWCELL_INTERBUF(pDResInfo);
×
7151

7152
  SResultRowEntryInfo* pSResInfo = GET_RES_INFO(pSourceCtx);
×
7153
  SGroupKeyInfo*       pSBuf = GET_ROWCELL_INTERBUF(pSResInfo);
×
7154

7155
  // escape rest of data blocks to avoid first entry to be overwritten.
7156
  if (pDBuf->hasResult) {
×
7157
    goto _group_key_over;
×
7158
  }
7159

7160
  if (pSBuf->isNull) {
×
7161
    pDBuf->isNull = true;
×
7162
    pDBuf->hasResult = true;
×
7163
    goto _group_key_over;
×
7164
  }
7165

7166
  if (IS_VAR_DATA_TYPE(pSourceCtx->resDataInfo.type)) {
×
7167
    (void)memcpy(pDBuf->data, pSBuf->data,
×
7168
                 (pSourceCtx->resDataInfo.type == TSDB_DATA_TYPE_JSON) ? getJsonValueLen(pSBuf->data)
×
7169
                                                                       : varDataTLen(pSBuf->data));
×
7170
  } else {
7171
    (void)memcpy(pDBuf->data, pSBuf->data, pSourceCtx->resDataInfo.bytes);
×
7172
  }
7173

7174
  pDBuf->hasResult = true;
×
7175

7176
_group_key_over:
×
7177

7178
  SET_VAL(pDResInfo, 1, 1);
×
7179
  return TSDB_CODE_SUCCESS;
×
7180
}
7181

7182
int32_t cachedLastRowFunction(SqlFunctionCtx* pCtx) {
4,421✔
7183
  int32_t numOfElems = 0;
4,421✔
7184

7185
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
4,421✔
7186
  SFirstLastRes*       pInfo = GET_ROWCELL_INTERBUF(pResInfo);
4,421✔
7187

7188
  SInputColumnInfoData* pInput = &pCtx->input;
4,421✔
7189
  SColumnInfoData*      pInputCol = pInput->pData[0];
4,421✔
7190

7191
  int32_t bytes = pInputCol->info.bytes;
4,421✔
7192
  pInfo->bytes = bytes;
4,421✔
7193

7194
  SColumnInfoData* pkCol = pInput->pPrimaryKey;
4,421✔
7195
  pInfo->pkType = -1;
4,421✔
7196
  __compar_fn_t pkCompareFn = NULL;
4,421✔
7197
  if (pCtx->hasPrimaryKey) {
4,421✔
7198
    pInfo->pkType = pkCol->info.type;
20✔
7199
    pInfo->pkBytes = pkCol->info.bytes;
20✔
7200
    pkCompareFn = getKeyComparFunc(pInfo->pkType, TSDB_ORDER_DESC);
20✔
7201
  }
7202

7203
  // TODO it traverse the different way.
7204
  // last_row function does not ignore the null value
7205
  for (int32_t i = pInput->numOfRows + pInput->startRowIndex - 1; i >= pInput->startRowIndex; --i) {
8,851✔
7206
    numOfElems++;
4,431✔
7207

7208
    bool  isNull = colDataIsNull(pInputCol, pInput->numOfRows, i, NULL);
4,431✔
7209
    char* data = isNull ? NULL : colDataGetData(pInputCol, i);
4,431!
7210

7211
    TSKEY cts = getRowPTs(pInput->pPTS, i);
4,431!
7212
    if (pResInfo->numOfRes == 0 || pInfo->ts < cts) {
4,431✔
7213
      int32_t code = doSaveLastrow(pCtx, data, i, cts, pInfo);
3,988✔
7214
      if (code != TSDB_CODE_SUCCESS) {
3,987!
7215
        return code;
×
7216
      }
7217
      pResInfo->numOfRes = 1;
3,987✔
7218
    }
7219
  }
7220

7221
  SET_VAL(pResInfo, numOfElems, 1);
4,420!
7222
  return TSDB_CODE_SUCCESS;
4,420✔
7223
}
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