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

taosdata / TDengine / #5011

03 Apr 2026 03:59PM UTC coverage: 72.3% (+0.008%) from 72.292%
#5011

push

travis-ci

web-flow
merge: from main to 3.0 branch #35067

4053 of 5985 new or added lines in 68 files covered. (67.72%)

732 existing lines in 143 files now uncovered.

257430 of 356056 relevant lines covered (72.3%)

131834103.52 hits per line

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

75.67
/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 "decimal.h"
19
#include "function.h"
20
#include "functionResInfoInt.h"
21
#include "geosWrapper.h"
22
#include "query.h"
23
#include "querynodes.h"
24
#include "tanalytics.h"
25
#include "tarray.h"
26
#include "tcompare.h"
27
#include "tdatablock.h"
28
#include "tdigest.h"
29
#include "tfunctionInt.h"
30
#include "tglobal.h"
31
#include "thistogram.h"
32
#include "tpercentile.h"
33
#include "ttime.h"
34
#include "ttypes.h"
35

36
bool ignoreNegative(int8_t ignoreOption) { return (ignoreOption & 0x1) == 0x1; }
2,147,483,647✔
37
bool ignoreNull(int8_t ignoreOption) { return (ignoreOption & 0x2) == 0x2; }
45,398,997✔
38

39
typedef enum {
40
  APERCT_ALGO_UNKNOWN = 0,
41
  APERCT_ALGO_DEFAULT,
42
  APERCT_ALGO_TDIGEST,
43
} EAPerctAlgoType;
44

45
typedef enum { UNKNOWN_BIN = 0, USER_INPUT_BIN, LINEAR_BIN, LOG_BIN } EHistoBinType;
46

47
typedef enum {
48
  STATE_OPER_INVALID = 0,
49
  STATE_OPER_LT,
50
  STATE_OPER_GT,
51
  STATE_OPER_LE,
52
  STATE_OPER_GE,
53
  STATE_OPER_NE,
54
  STATE_OPER_EQ,
55
} EStateOperType;
56

57
#define SET_VAL(_info, numOfElem, res) \
58
  do {                                 \
59
    if ((numOfElem) <= 0) {            \
60
      break;                           \
61
    }                                  \
62
    (_info)->numOfRes = (res);         \
63
  } while (0)
64

65
#define GET_TS_LIST(x)    ((TSKEY*)((x)->ptsList))
66
#define GET_TS_DATA(x, y) (GET_TS_LIST(x)[(y)])
67

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

80
#define UPDATE_DATA(ctx, left, right, num, sign, _ts) \
81
  do {                                                \
82
    if (((left) < (right)) ^ (sign)) {                \
83
      (left) = (right);                               \
84
      DO_UPDATE_SUBSID_RES(ctx, _ts);                 \
85
      (num) += 1;                                     \
86
    }                                                 \
87
  } while (0)
88

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

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

113
#define LIST_ADD_DECIMAL_N(_res, _col, _start, _rows, _t, numOfElem)                                  \
114
  do {                                                                                                \
115
    _t*                d = (_t*)(_col->pData);                                                        \
116
    const SDecimalOps* pOps = getDecimalOps(TSDB_DATA_TYPE_DECIMAL);                                  \
117
    for (int32_t i = (_start); i < (_rows) + (_start); ++i) {                                         \
118
      if (((_col)->hasNull) && colDataIsNull_f(_col, i)) {                                            \
119
        continue;                                                                                     \
120
      };                                                                                              \
121
      overflow = overflow || decimal128AddCheckOverflow((Decimal*)_res, d + i, DECIMAL_WORD_NUM(_t)); \
122
      if (overflow) break;                                                                            \
123
      pOps->add(_res, d + i, DECIMAL_WORD_NUM(_t));                                                   \
124
      (numOfElem)++;                                                                                  \
125
    }                                                                                                 \
126
  } while (0)
127

128
#define LIST_SUB_N(_res, _col, _start, _rows, _t, numOfElem)  \
129
  do {                                                        \
130
    _t* d = (_t*)(_col->pData);                               \
131
    for (int32_t i = (_start); i < (_rows) + (_start); ++i) { \
132
      if (((_col)->hasNull) && colDataIsNull_f(_col, i)) {    \
133
        continue;                                             \
134
      };                                                      \
135
      (_res) -= (d)[i];                                       \
136
      (numOfElem)++;                                          \
137
    }                                                         \
138
  } while (0)
139

140
#define LIST_STDDEV_SUB_N(sumT, T)                                 \
141
  do {                                                             \
142
    T* plist = (T*)pCol->pData;                                    \
143
    for (int32_t i = start; i < numOfRows + start; ++i) {          \
144
      if (pCol->hasNull && colDataIsNull_f(pCol, i)) {             \
145
        continue;                                                  \
146
      }                                                            \
147
      numOfElem += 1;                                              \
148
      pStddevRes->count -= 1;                                      \
149
      sumT -= plist[i];                                            \
150
      pStddevRes->quadraticISum -= (int64_t)(plist[i] * plist[i]); \
151
    }                                                              \
152
  } while (0)
153

154
#define LEASTSQR_CAL(p, x, y, index, step) \
155
  do {                                     \
156
    (p)[0][0] += (double)(x) * (x);        \
157
    (p)[0][1] += (double)(x);              \
158
    (p)[0][2] += (double)(x) * (y)[index]; \
159
    (p)[1][2] += (y)[index];               \
160
    (x) += step;                           \
161
  } while (0)
162

163
#define STATE_COMP(_op, _lval, _param) STATE_COMP_IMPL(_op, _lval, GET_STATE_VAL(_param))
164

165
#define GET_STATE_VAL(param) ((param.nType == TSDB_DATA_TYPE_BIGINT) ? (param.i) : (param.d))
166

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

193
#define INIT_INTP_POINT(_p, _k, _v) \
194
  do {                              \
195
    (_p).key = (_k);                \
196
    (_p).val = (_v);                \
197
  } while (0)
198

199
void funcInputUpdate(SqlFunctionCtx* pCtx) {
55,178,075✔
200
  SFuncInputRowIter* pIter = &pCtx->rowIter;
55,178,075✔
201

202
  if (!pCtx->bInputFinished) {
55,178,075✔
203
    pIter->pInput = &pCtx->input;
55,178,075✔
204
    pIter->tsList = (TSKEY*)pIter->pInput->pPTS->pData;
55,178,075✔
205
    pIter->pDataCol = pIter->pInput->pData[0];
55,177,634✔
206
    pIter->pPkCol = pIter->pInput->pPrimaryKey;
55,177,634✔
207
    pIter->rowIndex = pIter->pInput->startRowIndex;
55,177,193✔
208
    pIter->inputEndIndex = pIter->rowIndex + pIter->pInput->numOfRows - 1;
55,177,634✔
209
    pIter->pSrcBlock = pCtx->pSrcBlock;
55,177,634✔
210
    if (!pIter->hasGroupId || pIter->groupId != pIter->pSrcBlock->info.id.groupId) {
55,177,634✔
211
      pIter->hasGroupId = true;
6,848,801✔
212
      pIter->groupId = pIter->pSrcBlock->info.id.groupId;
6,848,360✔
213
      pIter->hasPrev = false;
6,848,801✔
214
    }
215
  } else {
216
    pIter->finalRow = true;
×
217
  }
218
}
55,177,634✔
219

220
int32_t funcInputGetNextRowDescPk(SFuncInputRowIter* pIter, SFuncInputRow* pRow, bool* res) {
×
221
  if (pIter->finalRow) {
×
222
    if (pIter->hasPrev) {
×
223
      pRow->ts = pIter->prevBlockTsEnd;
×
224
      pRow->isDataNull = pIter->prevIsDataNull;
×
225
      pRow->pData = pIter->pPrevData;
×
226
      pRow->block = pIter->pPrevRowBlock;
×
227
      pRow->rowIndex = 0;
×
228

229
      pIter->hasPrev = false;
×
230
      *res = true;
×
231
      return TSDB_CODE_SUCCESS;
×
232
    } else {
233
      *res = false;
×
234
      return TSDB_CODE_SUCCESS;
×
235
    }
236
  }
237
  if (pIter->hasPrev) {
×
238
    if (pIter->prevBlockTsEnd == pIter->tsList[pIter->inputEndIndex]) {
×
239
      blockDataDestroy(pIter->pPrevRowBlock);
×
240
      int32_t code = blockDataExtractBlock(pIter->pSrcBlock, pIter->inputEndIndex, 1, &pIter->pPrevRowBlock);
×
241
      if (code) {
×
242
        return code;
×
243
      }
244

NEW
245
      pIter->prevIsDataNull = colDataIsNull_s(pIter->pDataCol, pIter->inputEndIndex);
×
246

247
      pIter->pPrevData = taosMemoryMalloc(pIter->pDataCol->info.bytes);
×
248
      if (NULL == pIter->pPrevData) {
×
249
        qError("out of memory when function get input row.");
×
250
        return terrno;
×
251
      }
252
      char* srcData = colDataGetData(pIter->pDataCol, pIter->inputEndIndex);
×
253
      (void)memcpy(pIter->pPrevData, srcData, pIter->pDataCol->info.bytes);
×
254

255
      pIter->pPrevPk = taosMemoryMalloc(pIter->pPkCol->info.bytes);
×
256
      if (NULL == pIter->pPrevPk) {
×
257
        qError("out of memory when function get input row.");
×
258
        taosMemoryFree(pIter->pPrevData);
×
259
        return terrno;
×
260
      }
261
      char* pkData = colDataGetData(pIter->pPkCol, pIter->inputEndIndex);
×
262
      (void)memcpy(pIter->pPrevPk, pkData, pIter->pPkCol->info.bytes);
×
263

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

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

327
      int32_t code = blockDataExtractBlock(pIter->pSrcBlock, pIter->inputEndIndex, 1, &pIter->pPrevRowBlock);
×
328
      *res = false;
×
329
      return code;
×
330
    }
331
  }
332
}
333

334
static void forwardToNextDiffTsRow(SFuncInputRowIter* pIter, int32_t rowIndex) {
4,075,832✔
335
  int32_t idx = rowIndex + 1;
4,075,832✔
336
  while (idx <= pIter->inputEndIndex && pIter->tsList[idx] == pIter->tsList[rowIndex]) {
54,638,352✔
337
    ++idx;
50,562,520✔
338
  }
339
  pIter->rowIndex = idx;
4,075,832✔
340
}
4,075,832✔
341

342
static void setInputRowInfo(SFuncInputRow* pRow, SFuncInputRowIter* pIter, int32_t rowIndex, bool setPk) {
2,147,483,647✔
343
  pRow->ts = pIter->tsList[rowIndex];
2,147,483,647✔
344
  pRow->ts = pIter->tsList[rowIndex];
2,147,483,647✔
345
  pRow->isDataNull = colDataIsNull_s(pIter->pDataCol, rowIndex);
2,147,483,647✔
346
  pRow->pData = colDataGetData(pIter->pDataCol, rowIndex);
2,147,483,647✔
347
  pRow->pPk = setPk ? colDataGetData(pIter->pPkCol, rowIndex) : NULL;
2,147,483,647✔
348
  pRow->block = pIter->pSrcBlock;
2,147,483,647✔
349
  pRow->rowIndex = rowIndex;
2,147,483,647✔
350
}
2,147,483,647✔
351

352
bool funcInputGetNextRowAscPk(SFuncInputRowIter* pIter, SFuncInputRow* pRow) {
4,614,190✔
353
  if (pIter->hasPrev) {
4,614,190✔
354
    if (pIter->prevBlockTsEnd == pIter->tsList[pIter->inputEndIndex]) {
46,080✔
355
      pIter->hasPrev = true;
×
356
      return false;
×
357
    } else {
358
      int32_t idx = pIter->rowIndex;
46,080✔
359
      while (pIter->tsList[idx] == pIter->prevBlockTsEnd) {
46,080✔
360
        ++idx;
×
361
      }
362

363
      pIter->hasPrev = false;
46,080✔
364
      setInputRowInfo(pRow, pIter, idx, true);
46,080✔
365
      forwardToNextDiffTsRow(pIter, idx);
46,080✔
366
      return true;
46,080✔
367
    }
368
  } else {
369
    if (pIter->rowIndex <= pIter->inputEndIndex) {
4,568,110✔
370
      setInputRowInfo(pRow, pIter, pIter->rowIndex, true);
4,299,372✔
371

372
      TSKEY tsEnd = pIter->tsList[pIter->inputEndIndex];
4,299,372✔
373
      if (pIter->tsList[pIter->rowIndex] != tsEnd) {
4,299,372✔
374
        forwardToNextDiffTsRow(pIter, pIter->rowIndex);
4,029,752✔
375
      } else {
376
        pIter->rowIndex = pIter->inputEndIndex + 1;
269,620✔
377
      }
378
      return true;
4,299,372✔
379
    } else {
380
      TSKEY tsEnd = pIter->tsList[pIter->inputEndIndex];
268,738✔
381
      pIter->hasPrev = true;
268,738✔
382
      pIter->prevBlockTsEnd = tsEnd;
268,738✔
383
      return false;
268,738✔
384
    }
385
  }
386
}
387

388
bool funcInputGetNextRowNoPk(SFuncInputRowIter* pIter, SFuncInputRow* pRow) {
2,147,483,647✔
389
  if (pIter->rowIndex <= pIter->inputEndIndex) {
2,147,483,647✔
390
    setInputRowInfo(pRow, pIter, pIter->rowIndex, false);
2,147,483,647✔
391
    ++pIter->rowIndex;
2,147,483,647✔
392
    return true;
2,147,483,647✔
393
  } else {
394
    return false;
55,487,338✔
395
  }
396
}
397

398
int32_t funcInputGetNextRow(SqlFunctionCtx* pCtx, SFuncInputRow* pRow, bool* res) {
2,147,483,647✔
399
  SFuncInputRowIter* pIter = &pCtx->rowIter;
2,147,483,647✔
400
  if (pCtx->hasPrimaryKey) {
2,147,483,647✔
401
    if (pCtx->order == TSDB_ORDER_DESC) {
4,614,190✔
402
      return funcInputGetNextRowDescPk(pIter, pRow, res);
×
403
      return TSDB_CODE_SUCCESS;
404
    } else {
405
      *res = funcInputGetNextRowAscPk(pIter, pRow);
4,614,190✔
406
    }
407
  } else {
408
    *res = funcInputGetNextRowNoPk(pIter, pRow);
2,147,483,647✔
409
    return TSDB_CODE_SUCCESS;
2,147,483,647✔
410
  }
411
  return TSDB_CODE_SUCCESS;
4,614,190✔
412
}
413

414
// This function append the selectivity to subsidiaries function context directly, without fetching data
415
// from intermediate disk based buf page
416
int32_t appendSelectivityCols(SqlFunctionCtx* pCtx, SSDataBlock* pSrcBlock, int32_t rowIndex, int32_t pos) {
2,147,483,647✔
417
  if (pCtx->subsidiaries.num <= 0) {
2,147,483,647✔
418
    return TSDB_CODE_SUCCESS;
×
419
  }
420

421
  for (int32_t j = 0; j < pCtx->subsidiaries.num; ++j) {
2,147,483,647✔
422
    SqlFunctionCtx* pc = pCtx->subsidiaries.pCtx[j];
2,147,483,647✔
423

424
    // get data from source col
425
    SFunctParam* pFuncParam = &pc->pExpr->base.pParam[0];
2,147,483,647✔
426
    int32_t      srcSlotId = pFuncParam->pCol->slotId;
2,147,483,647✔
427

428
    SColumnInfoData* pSrcCol = taosArrayGet(pSrcBlock->pDataBlock, srcSlotId);
2,147,483,647✔
429
    if (NULL == pSrcCol) {
2,147,483,647✔
430
      return TSDB_CODE_OUT_OF_RANGE;
×
431
    }
432

433
    char* pData = colDataGetData(pSrcCol, rowIndex);
2,147,483,647✔
434

435
    // append to dest col
436
    int32_t dstSlotId = pc->pExpr->base.resSchema.slotId;
2,147,483,647✔
437

438
    SColumnInfoData* pDstCol = taosArrayGet(pCtx->pDstBlock->pDataBlock, dstSlotId);
2,147,483,647✔
439
    if (NULL == pDstCol) {
2,147,483,647✔
440
      return TSDB_CODE_OUT_OF_RANGE;
×
441
    }
442
    if (colDataIsNull_s(pSrcCol, rowIndex) == true) {
2,147,483,647✔
443
      colDataSetNULL(pDstCol, pos);
4,005✔
444
    } else {
445
      int32_t code = colDataSetVal(pDstCol, pos, pData, false);
2,147,483,647✔
446
      if (TSDB_CODE_SUCCESS != code) {
2,147,483,647✔
447
        return code;
×
448
      }
449
    }
450
  }
451
  return TSDB_CODE_SUCCESS;
2,147,483,647✔
452
}
453

454
bool funcInputGetNextRowIndex(SInputColumnInfoData* pInput, int32_t from, bool firstOccur, int32_t* pRowIndex,
455
                              int32_t* nextFrom);
456

457
static bool firstLastTransferInfoImpl(SFirstLastRes* pInput, SFirstLastRes* pOutput, bool isFirst);
458

459
int32_t functionSetup(SqlFunctionCtx* pCtx, SResultRowEntryInfo* pResultInfo) {
2,147,483,647✔
460
  if (pResultInfo->initialized) {
2,147,483,647✔
461
    return TSDB_CODE_SUCCESS;  // already initialized
1,959,851✔
462
  }
463

464
  if (pCtx->pOutput != NULL) {
2,147,483,647✔
465
    (void)memset(pCtx->pOutput, 0, (size_t)pCtx->resDataInfo.bytes);
×
466
  }
467

468
  initResultRowEntry(pResultInfo, pCtx->resDataInfo.interBufSize);
2,147,483,647✔
469
  return TSDB_CODE_SUCCESS;
2,147,483,647✔
470
}
471

472
int32_t functionFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
2,147,483,647✔
473
  int32_t          code = TSDB_CODE_SUCCESS;
2,147,483,647✔
474
  int32_t          slotId = pCtx->pExpr->base.resSchema.slotId;
2,147,483,647✔
475
  SColumnInfoData* pCol = taosArrayGet(pBlock->pDataBlock, slotId);
2,147,483,647✔
476
  if (NULL == pCol) {
2,147,483,647✔
477
    return TSDB_CODE_OUT_OF_RANGE;
×
478
  }
479
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
2,147,483,647✔
480
  pResInfo->isNullRes = (pResInfo->numOfRes == 0) ? 1 : 0;
2,147,483,647✔
481

482
  char* in = GET_ROWCELL_INTERBUF(pResInfo);
2,147,483,647✔
483
  code = colDataSetVal(pCol, pBlock->info.rows, in, pResInfo->isNullRes);
2,147,483,647✔
484

485
  return code;
2,147,483,647✔
486
}
487

488
int32_t firstCombine(SqlFunctionCtx* pDestCtx, SqlFunctionCtx* pSourceCtx) {
×
489
  SResultRowEntryInfo* pDResInfo = GET_RES_INFO(pDestCtx);
×
490
  SFirstLastRes*       pDBuf = GET_ROWCELL_INTERBUF(pDResInfo);
×
491
  int32_t              bytes = pDBuf->bytes;
×
492

493
  SResultRowEntryInfo* pSResInfo = GET_RES_INFO(pSourceCtx);
×
494
  SFirstLastRes*       pSBuf = GET_ROWCELL_INTERBUF(pSResInfo);
×
495

496
  pDBuf->hasResult = firstLastTransferInfoImpl(pSBuf, pDBuf, true);
×
497

498
  pDResInfo->numOfRes = TMAX(pDResInfo->numOfRes, pSResInfo->numOfRes);
×
499
  pDResInfo->isNullRes &= pSResInfo->isNullRes;
×
500
  return TSDB_CODE_SUCCESS;
×
501
}
502

503
int32_t functionFinalizeWithResultBuf(SqlFunctionCtx* pCtx, SSDataBlock* pBlock, char* finalResult) {
83,790✔
504
  int32_t          slotId = pCtx->pExpr->base.resSchema.slotId;
83,790✔
505
  SColumnInfoData* pCol = taosArrayGet(pBlock->pDataBlock, slotId);
83,790✔
506
  if (NULL == pCol) {
83,790✔
507
    return TSDB_CODE_OUT_OF_RANGE;
×
508
  }
509
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
83,790✔
510
  pResInfo->isNullRes = (pResInfo->numOfRes == 0) ? 1 : 0;
83,790✔
511

512
  char*   in = finalResult;
83,790✔
513
  int32_t code = colDataSetVal(pCol, pBlock->info.rows, in, pResInfo->isNullRes);
83,790✔
514

515
  return code;
83,790✔
516
}
517

518
EFuncDataRequired countDataRequired(SFunctionNode* pFunc, STimeWindow* pTimeWindow) {
15,021,275✔
519
  SNode* pParam = nodesListGetNode(pFunc->pParameterList, 0);
15,021,275✔
520
  if (QUERY_NODE_COLUMN == nodeType(pParam) && PRIMARYKEY_TIMESTAMP_COL_ID == ((SColumnNode*)pParam)->colId) {
15,022,215✔
521
    return FUNC_DATA_REQUIRED_NOT_LOAD;
10,998,790✔
522
  }
523
  return FUNC_DATA_REQUIRED_SMA_LOAD;
4,023,281✔
524
}
525

526
bool getCountFuncEnv(SFunctionNode* UNUSED_PARAM(pFunc), SFuncExecEnv* pEnv) {
53,052,037✔
527
  pEnv->calcMemSize = sizeof(int64_t);
53,052,037✔
528
  return true;
53,063,990✔
529
}
530

531
static int64_t getNumOfElems(SqlFunctionCtx* pCtx) {
2,147,483,647✔
532
  int64_t numOfElem = 0;
2,147,483,647✔
533

534
  /*
535
   * 1. column data missing (schema modified) causes pInputCol->hasNull == true. pInput->colDataSMAIsSet == true;
536
   * 2. for general non-primary key columns, pInputCol->hasNull may be true or false, pInput->colDataSMAIsSet == true;
537
   * 3. for primary key column, pInputCol->hasNull always be false, pInput->colDataSMAIsSet == false;
538
   */
539
  SInputColumnInfoData* pInput = &pCtx->input;
2,147,483,647✔
540
  SColumnInfoData*      pInputCol = pInput->pData[0];
2,147,483,647✔
541
  if (1 == pInput->numOfRows && pInput->blankFill) {
2,147,483,647✔
542
    return 0;
54,542,570✔
543
  }
544
  if (pInput->colDataSMAIsSet && pInput->totalRows == pInput->numOfRows) {
2,147,483,647✔
545
    numOfElem = pInput->numOfRows - pInput->pColumnDataAgg[0]->numOfNull;
826,159✔
546
  } else {
547
    if (pInputCol->hasNull) {
2,147,483,647✔
548
      for (int32_t i = pInput->startRowIndex; i < pInput->startRowIndex + pInput->numOfRows; ++i) {
2,147,483,647✔
549
        if (colDataIsNull(pInputCol, pInput->totalRows, i, NULL)) {
2,147,483,647✔
550
          continue;
2,147,483,647✔
551
        }
552
        numOfElem += 1;
2,147,483,647✔
553
      }
554
    } else {
555
      // when counting on the primary time stamp column and no statistics data is presented, use the size value
556
      // directly.
557
      numOfElem = pInput->numOfRows;
2,147,483,647✔
558
    }
559
  }
560
  return numOfElem;
2,147,483,647✔
561
}
562

563
/*
564
 * count function does need the finalize, if data is missing, the default value, which is 0, is used
565
 * count function does not use the pCtx->interResBuf to keep the intermediate buffer
566
 */
567
int32_t countFunction(SqlFunctionCtx* pCtx) {
2,147,483,647✔
568
  int64_t numOfElem = 0;
2,147,483,647✔
569

570
  SResultRowEntryInfo*  pResInfo = GET_RES_INFO(pCtx);
2,147,483,647✔
571
  SInputColumnInfoData* pInput = &pCtx->input;
2,147,483,647✔
572

573
  int32_t type = pInput->pData[0]->info.type;
2,147,483,647✔
574

575
  char*   buf = GET_ROWCELL_INTERBUF(pResInfo);
2,147,483,647✔
576
  int64_t val = *((int64_t*)buf);
2,147,483,647✔
577
  if (IS_NULL_TYPE(type)) {
2,147,483,647✔
578
    // select count(NULL) returns 0
579
    numOfElem = 1;
4,612,841✔
580
    val += 0;
4,612,841✔
581
  } else {
582
    numOfElem = getNumOfElems(pCtx);
2,147,483,647✔
583
    val += numOfElem;
2,147,483,647✔
584
  }
585
  taosSetInt64Aligned((int64_t*)buf, val);
586

587
  if (tsCountAlwaysReturnValue) {
2,147,483,647✔
588
    pResInfo->numOfRes = 1;
2,147,483,647✔
589
  } else {
590
    SET_VAL(pResInfo, val, 1);
9,299,106✔
591
  }
592

593
  return TSDB_CODE_SUCCESS;
2,147,483,647✔
594
}
595

596
int32_t combineFunction(SqlFunctionCtx* pDestCtx, SqlFunctionCtx* pSourceCtx) {
×
597
  SResultRowEntryInfo* pDResInfo = GET_RES_INFO(pDestCtx);
×
598
  char*                pDBuf = GET_ROWCELL_INTERBUF(pDResInfo);
×
599

600
  SResultRowEntryInfo* pSResInfo = GET_RES_INFO(pSourceCtx);
×
601
  char*                pSBuf = GET_ROWCELL_INTERBUF(pSResInfo);
×
602
  *((int64_t*)pDBuf) += *((int64_t*)pSBuf);
×
603

604
  SET_VAL(pDResInfo, *((int64_t*)pDBuf), 1);
×
605
  return TSDB_CODE_SUCCESS;
×
606
}
607

608
int32_t sumFunction(SqlFunctionCtx* pCtx) {
2,147,483,647✔
609
  int32_t numOfElem = 0;
2,147,483,647✔
610

611
  // Only the pre-computing information loaded and actual data does not loaded
612
  SInputColumnInfoData* pInput = &pCtx->input;
2,147,483,647✔
613
  SColumnDataAgg*       pAgg = pInput->pColumnDataAgg[0];
2,147,483,647✔
614
  int32_t               type = pInput->pData[0]->info.type;
2,147,483,647✔
615
  pCtx->inputType = type;
2,147,483,647✔
616

617
  void* pSumRes = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
2,147,483,647✔
618
  SUM_RES_SET_TYPE(pSumRes, pCtx->inputType, type);
2,147,483,647✔
619

620
  if (IS_NULL_TYPE(type)) {
2,147,483,647✔
621
    numOfElem = 0;
355,481✔
622
    goto _sum_over;
355,481✔
623
  }
624

625
  if (pInput->colDataSMAIsSet) {
2,147,483,647✔
626
    numOfElem = pInput->numOfRows - pAgg->numOfNull;
32,403,633✔
627

628
    if (IS_SIGNED_NUMERIC_TYPE(type)) {
32,398,657✔
629
      SUM_RES_INC_ISUM(pSumRes, pAgg->sum);
16,497,686✔
630
    } else if (IS_UNSIGNED_NUMERIC_TYPE(type)) {
15,900,971✔
631
      SUM_RES_INC_USUM(pSumRes, pAgg->sum);
15,907,682✔
632
    } else if (IS_FLOAT_TYPE(type)) {
1,375✔
UNCOV
633
      SUM_RES_INC_DSUM(pSumRes, GET_DOUBLE_VAL((const char*)&(pAgg->sum)));
×
634
    } else if (IS_DECIMAL_TYPE(type)) {
8,217✔
635
      SUM_RES_SET_TYPE(pSumRes, pCtx->inputType, TSDB_DATA_TYPE_DECIMAL);
8,217✔
636
      const SDecimalOps* pOps = getDecimalOps(TSDB_DATA_TYPE_DECIMAL);
8,217✔
637
      if (pAgg->overflow || decimal128AddCheckOverflow((Decimal*)&SUM_RES_GET_DECIMAL_SUM(pSumRes),
14,940✔
638
                                                       &pAgg->decimal128Sum, DECIMAL_WORD_NUM(Decimal))) {
6,723✔
639
        return TSDB_CODE_DECIMAL_OVERFLOW;
1,494✔
640
      }
641
      pOps->add(&SUM_RES_GET_DECIMAL_SUM(pSumRes), &pAgg->decimal128Sum, DECIMAL_WORD_NUM(Decimal));
6,723✔
642
    }
643
  } else {  // computing based on the true data block
644
    SColumnInfoData* pCol = pInput->pData[0];
2,147,483,647✔
645

646
    int32_t start = pInput->startRowIndex;
2,147,483,647✔
647
    int32_t numOfRows = pInput->numOfRows;
2,147,483,647✔
648

649
    if (IS_SIGNED_NUMERIC_TYPE(type) || type == TSDB_DATA_TYPE_BOOL) {
2,147,483,647✔
650
      if (type == TSDB_DATA_TYPE_TINYINT || type == TSDB_DATA_TYPE_BOOL) {
2,147,483,647✔
651
        LIST_ADD_N(SUM_RES_GET_ISUM(pSumRes), pCol, start, numOfRows, int8_t, numOfElem);
794,660,785✔
652
      } else if (type == TSDB_DATA_TYPE_SMALLINT) {
2,147,483,647✔
653
        LIST_ADD_N(SUM_RES_GET_ISUM(pSumRes), pCol, start, numOfRows, int16_t, numOfElem);
485,588,267✔
654
      } else if (type == TSDB_DATA_TYPE_INT) {
2,147,483,647✔
655
        LIST_ADD_N(SUM_RES_GET_ISUM(pSumRes), pCol, start, numOfRows, int32_t, numOfElem);
2,147,483,647✔
656
      } else if (type == TSDB_DATA_TYPE_BIGINT) {
1,222,420,403✔
657
        LIST_ADD_N(SUM_RES_GET_ISUM(pSumRes), pCol, start, numOfRows, int64_t, numOfElem);
2,147,483,647✔
658
      }
659
    } else if (IS_UNSIGNED_NUMERIC_TYPE(type)) {
2,147,483,647✔
660
      if (type == TSDB_DATA_TYPE_UTINYINT) {
2,147,483,647✔
661
        LIST_ADD_N(SUM_RES_GET_USUM(pSumRes), pCol, start, numOfRows, uint8_t, numOfElem);
482,475,105✔
662
      } else if (type == TSDB_DATA_TYPE_USMALLINT) {
2,147,483,647✔
663
        LIST_ADD_N(SUM_RES_GET_USUM(pSumRes), pCol, start, numOfRows, uint16_t, numOfElem);
2,147,483,647✔
664
      } else if (type == TSDB_DATA_TYPE_UINT) {
4,131,989✔
665
        LIST_ADD_N(SUM_RES_GET_USUM(pSumRes), pCol, start, numOfRows, uint32_t, numOfElem);
394,006,641✔
666
      } else if (type == TSDB_DATA_TYPE_UBIGINT) {
2,179,230✔
667
        LIST_ADD_N(SUM_RES_GET_USUM(pSumRes), pCol, start, numOfRows, uint64_t, numOfElem);
395,418,311✔
668
      }
669
    } else if (type == TSDB_DATA_TYPE_DOUBLE) {
195,571,196✔
670
      LIST_ADD_N(SUM_RES_GET_DSUM(pSumRes), pCol, start, numOfRows, double, numOfElem);
486,964,426✔
671
    } else if (type == TSDB_DATA_TYPE_FLOAT) {
142,660,343✔
672
      LIST_ADD_N(SUM_RES_GET_DSUM(pSumRes), pCol, start, numOfRows, float, numOfElem);
446,075,159✔
673
    } else if (IS_DECIMAL_TYPE(type)) {
17,334✔
674
      SUM_RES_SET_TYPE(pSumRes, pCtx->inputType, TSDB_DATA_TYPE_DECIMAL);
17,334✔
675
      int32_t overflow = false;
22,410✔
676
      if (TSDB_DATA_TYPE_DECIMAL64 == type) {
22,410✔
677
        LIST_ADD_DECIMAL_N(&SUM_RES_GET_DECIMAL_SUM(pSumRes), pCol, start, numOfRows, Decimal64, numOfElem);
5,981,976✔
678
      } else if (TSDB_DATA_TYPE_DECIMAL == type) {
16,434✔
679
        LIST_ADD_DECIMAL_N(&SUM_RES_GET_DECIMAL_SUM(pSumRes), pCol, start, numOfRows, Decimal128, numOfElem);
11,972,916✔
680
      }
681
      if (overflow) return TSDB_CODE_DECIMAL_OVERFLOW;
22,410✔
682
    }
683
  }
684

685
  // check for overflow
686
  if (IS_FLOAT_TYPE(type) && (isinf(SUM_RES_GET_DSUM(pSumRes)) || isnan(SUM_RES_GET_DSUM(pSumRes)))) {
2,147,483,647✔
687
    numOfElem = 0;
29✔
688
  }
689

690
_sum_over:
2,147,483,647✔
691
  if (numOfElem == 0) {
2,147,483,647✔
692
    if (tsCountAlwaysReturnValue && pCtx->pExpr->pExpr->_function.pFunctNode->hasOriginalFunc &&
1,712,573,508✔
693
        fmIsCountLikeFunc(pCtx->pExpr->pExpr->_function.pFunctNode->originalFuncId)) {
72,333,156✔
694
      numOfElem = 1;
×
695
    }
696
  }
697
  // data in the check operation are all null, not output
698
  SET_VAL(GET_RES_INFO(pCtx), numOfElem, 1);
2,147,483,647✔
699
  return TSDB_CODE_SUCCESS;
2,147,483,647✔
700
}
701

702
int32_t sumCombine(SqlFunctionCtx* pDestCtx, SqlFunctionCtx* pSourceCtx) {
×
703
  SResultRowEntryInfo* pDResInfo = GET_RES_INFO(pDestCtx);
×
704
  void*                pDBuf = GET_ROWCELL_INTERBUF(pDResInfo);
×
705
  int16_t              type = SUM_RES_GET_TYPE(pDBuf, pDestCtx->inputType);
×
706

707
  SResultRowEntryInfo* pSResInfo = GET_RES_INFO(pSourceCtx);
×
708
  void*                pSBuf = GET_ROWCELL_INTERBUF(pSResInfo);
×
709
  type = (type == TSDB_DATA_TYPE_NULL) ? SUM_RES_GET_TYPE(pSBuf, pDestCtx->inputType) : type;
×
710

711
  if (IS_SIGNED_NUMERIC_TYPE(type) || type == TSDB_DATA_TYPE_BOOL) {
×
712
    SUM_RES_INC_ISUM(pDBuf, SUM_RES_GET_ISUM(pSBuf));
×
713
  } else if (IS_UNSIGNED_NUMERIC_TYPE(type)) {
×
714
    SUM_RES_INC_USUM(pDBuf, SUM_RES_GET_USUM(pSBuf));
×
715
  } else if (IS_DECIMAL_TYPE(type)) {
×
716
    bool overflow = false;
×
717
    SUM_RES_INC_DECIMAL_SUM(pDBuf, &SUM_RES_GET_DECIMAL_SUM(pSBuf), type);
×
718
  } else if (type == TSDB_DATA_TYPE_DOUBLE || type == TSDB_DATA_TYPE_FLOAT) {
×
719
    SUM_RES_INC_DSUM(pDBuf, SUM_RES_GET_DSUM(pSBuf));
×
720
  }
721
  pDResInfo->numOfRes = TMAX(pDResInfo->numOfRes, pSResInfo->numOfRes);
×
722
  pDResInfo->isNullRes &= pSResInfo->isNullRes;
×
723
  return TSDB_CODE_SUCCESS;
×
724
}
725

726
bool getSumFuncEnv(SFunctionNode* pFunc, SFuncExecEnv* pEnv) {
25,788,244✔
727
  pEnv->calcMemSize = SUM_RES_GET_SIZE(pFunc->node.resType.type);
25,788,244✔
728
  return true;
25,790,314✔
729
}
730

731
static bool funcNotSupportStringSma(SFunctionNode* pFunc) {
24,592,265✔
732
  SNode* pParam;
733
  switch (pFunc->funcType) {
24,592,265✔
734
    case FUNCTION_TYPE_MAX:
24,595,874✔
735
    case FUNCTION_TYPE_MIN:
736
    case FUNCTION_TYPE_SUM:
737
    case FUNCTION_TYPE_AVG:
738
    case FUNCTION_TYPE_AVG_PARTIAL:
739
    case FUNCTION_TYPE_PERCENTILE:
740
    case FUNCTION_TYPE_SPREAD:
741
    case FUNCTION_TYPE_SPREAD_PARTIAL:
742
    case FUNCTION_TYPE_SPREAD_MERGE:
743
    case FUNCTION_TYPE_TWA:
744
    case FUNCTION_TYPE_ELAPSED:
745
      pParam = nodesListGetNode(pFunc->pParameterList, 0);
24,595,874✔
746
      if (pParam && nodesIsExprNode(pParam) && (IS_VAR_DATA_TYPE(((SExprNode*)pParam)->resType.type))) {
24,597,296✔
747
        return true;
1,504,968✔
748
      }
749
      break;
23,092,255✔
UNCOV
750
    default:
×
UNCOV
751
      break;
×
752
  }
753
  return false;
23,088,646✔
754
}
755

756
EFuncDataRequired statisDataRequired(SFunctionNode* pFunc, STimeWindow* pTimeWindow) {
24,592,495✔
757
  if (funcNotSupportStringSma(pFunc)) {
24,592,495✔
758
    return FUNC_DATA_REQUIRED_DATA_LOAD;
1,504,968✔
759
  }
760
  return FUNC_DATA_REQUIRED_SMA_LOAD;
23,092,345✔
761
}
762

763
int32_t minmaxFunctionSetup(SqlFunctionCtx* pCtx, SResultRowEntryInfo* pResultInfo) {
2,077,708,516✔
764
  if (pResultInfo->initialized) {
2,077,708,516✔
765
    return TSDB_CODE_SUCCESS;
×
766
  }
767
  if (TSDB_CODE_SUCCESS != functionSetup(pCtx, pResultInfo)) {
2,077,709,117✔
768
    return TSDB_CODE_FUNC_SETUP_ERROR;  // not initialized since it has been initialized
×
769
  }
770

771
  SMinmaxResInfo* buf = GET_ROWCELL_INTERBUF(pResultInfo);
2,077,712,888✔
772
  buf->assign = false;
2,077,715,173✔
773
  buf->tuplePos.pageId = -1;
2,077,716,869✔
774

775
  buf->nullTupleSaved = false;
2,077,712,792✔
776
  buf->nullTuplePos.pageId = -1;
2,077,718,138✔
777
  buf->str = NULL;
2,077,719,819✔
778
  return TSDB_CODE_SUCCESS;
2,077,708,209✔
779
}
780

781
bool getMinmaxFuncEnv(SFunctionNode* UNUSED_PARAM(pFunc), SFuncExecEnv* pEnv) {
37,522,782✔
782
  COMPILE_TIME_ASSERT(sizeof(SMinmaxResInfo) == sizeof(SOldMinMaxResInfo));
783
  pEnv->calcMemSize = sizeof(SMinmaxResInfo);
37,522,782✔
784
  return true;
37,524,857✔
785
}
786

787
int32_t minFunction(SqlFunctionCtx* pCtx) {
2,147,483,647✔
788
  int32_t numOfElems = 0;
2,147,483,647✔
789
  int32_t code = doMinMaxHelper(pCtx, 1, &numOfElems);
2,147,483,647✔
790
  if (code != TSDB_CODE_SUCCESS) {
2,147,483,647✔
791
    return code;
×
792
  }
793
  SET_VAL(GET_RES_INFO(pCtx), numOfElems, 1);
2,147,483,647✔
794
  return TSDB_CODE_SUCCESS;
2,147,483,647✔
795
}
796

797
int32_t maxFunction(SqlFunctionCtx* pCtx) {
2,147,483,647✔
798
  int32_t numOfElems = 0;
2,147,483,647✔
799
  int32_t code = doMinMaxHelper(pCtx, 0, &numOfElems);
2,147,483,647✔
800
  if (code != TSDB_CODE_SUCCESS) {
2,147,483,647✔
801
    return code;
×
802
  }
803
  SET_VAL(GET_RES_INFO(pCtx), numOfElems, 1);
2,147,483,647✔
804
  return TSDB_CODE_SUCCESS;
2,147,483,647✔
805
}
806

807
static int32_t setNullSelectivityValue(SqlFunctionCtx* pCtx, SSDataBlock* pBlock, int32_t rowIndex);
808
static int32_t setSelectivityValue(SqlFunctionCtx* pCtx, SSDataBlock* pBlock, const STuplePos* pTuplePos,
809
                                   int32_t rowIndex);
810

811
int32_t minmaxFunctionFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
2,043,452,914✔
812
  int32_t code = TSDB_CODE_SUCCESS;
2,043,452,914✔
813

814
  SResultRowEntryInfo* pEntryInfo = GET_RES_INFO(pCtx);
2,043,452,914✔
815
  SMinmaxResInfo*      pRes = GET_ROWCELL_INTERBUF(pEntryInfo);
2,043,453,314✔
816

817
  int32_t slotId = pCtx->pExpr->base.resSchema.slotId;
2,043,453,314✔
818
  int32_t currentRow = pBlock->info.rows;
2,043,453,314✔
819

820
  SColumnInfoData* pCol = taosArrayGet(pBlock->pDataBlock, slotId);
2,043,453,448✔
821
  if (NULL == pCol) {
2,043,454,536✔
822
    return TSDB_CODE_OUT_OF_RANGE;
×
823
  }
824
  pEntryInfo->isNullRes = (pEntryInfo->numOfRes == 0) ? 1 : 0;
2,043,454,536✔
825

826
  // NOTE: do nothing change it, for performance issue
827
  if (!pEntryInfo->isNullRes) {
2,043,454,597✔
828
    switch (pCol->info.type) {
1,740,632,454✔
829
      case TSDB_DATA_TYPE_UBIGINT:
145,383,047✔
830
      case TSDB_DATA_TYPE_BIGINT:
831
      case TSDB_DATA_TYPE_TIMESTAMP:
832
        ((int64_t*)pCol->pData)[currentRow] = pRes->v;
145,383,047✔
833
        break;
145,382,472✔
834
      case TSDB_DATA_TYPE_UINT:
1,482,072,002✔
835
      case TSDB_DATA_TYPE_INT:
836
        colDataSetInt32(pCol, currentRow, (int32_t*)&pRes->v);
1,482,072,002✔
837
        break;
1,482,072,002✔
838
      case TSDB_DATA_TYPE_USMALLINT:
19,600,508✔
839
      case TSDB_DATA_TYPE_SMALLINT:
840
        colDataSetInt16(pCol, currentRow, (int16_t*)&pRes->v);
19,600,508✔
841
        break;
19,600,508✔
842
      case TSDB_DATA_TYPE_BOOL:
36,560,839✔
843
      case TSDB_DATA_TYPE_UTINYINT:
844
      case TSDB_DATA_TYPE_TINYINT:
845
        colDataSetInt8(pCol, currentRow, (int8_t*)&pRes->v);
36,560,839✔
846
        break;
36,560,839✔
847
      case TSDB_DATA_TYPE_DOUBLE:
28,572,173✔
848
        colDataSetDouble(pCol, currentRow, (double*)&pRes->v);
28,572,173✔
849
        break;
28,572,173✔
850
      case TSDB_DATA_TYPE_FLOAT: {
23,068,533✔
851
        float v = GET_FLOAT_VAL(&pRes->v);
23,068,533✔
852
        colDataSetFloat(pCol, currentRow, &v);
23,068,934✔
853
        break;
23,068,934✔
854
      }
855
      case TSDB_DATA_TYPE_VARBINARY:
4,699,385✔
856
      case TSDB_DATA_TYPE_VARCHAR:
857
      case TSDB_DATA_TYPE_NCHAR: {
858
        code = colDataSetVal(pCol, currentRow, pRes->str, false);
4,699,385✔
859
        if (TSDB_CODE_SUCCESS != code) {
4,699,826✔
860
          return code;
×
861
        }
862
        break;
4,699,826✔
863
      }
864
      case TSDB_DATA_TYPE_DECIMAL64:
646,087✔
865
        code = colDataSetVal(pCol, currentRow, (const char*)&pRes->v, false);
646,087✔
866
        break;
646,087✔
867
      case TSDB_DATA_TYPE_DECIMAL:
31,159✔
868
        code = colDataSetVal(pCol, currentRow, (void*)pRes->dec, false);
31,159✔
869
        break;
31,159✔
870
    }
871
  } else {
872
    colDataSetNULL(pCol, currentRow);
302,822,584✔
873
  }
874

875
  if (IS_VAR_DATA_TYPE(pCol->info.type)) taosMemoryFreeClear(pRes->str);
2,043,453,072✔
876
  if (pCtx->subsidiaries.num > 0) {
2,043,454,368✔
877
    if (pEntryInfo->numOfRes > 0) {
2,204,562✔
878
      code = setSelectivityValue(pCtx, pBlock, &pRes->tuplePos, currentRow);
1,925,548✔
879
    } else {
880
      code = setNullSelectivityValue(pCtx, pBlock, currentRow);
279,014✔
881
    }
882
  }
883

884
  return code;
2,043,454,572✔
885
}
886

887
int32_t setNullSelectivityValue(SqlFunctionCtx* pCtx, SSDataBlock* pBlock, int32_t rowIndex) {
2,147,483,647✔
888
  if (pCtx->subsidiaries.num <= 0) {
2,147,483,647✔
889
    return TSDB_CODE_SUCCESS;
2,147,483,647✔
890
  }
891

892
  for (int32_t j = 0; j < pCtx->subsidiaries.num; ++j) {
946,804✔
893
    SqlFunctionCtx* pc = pCtx->subsidiaries.pCtx[j];
591,924✔
894
    int32_t         dstSlotId = pc->pExpr->base.resSchema.slotId;
591,924✔
895

896
    SColumnInfoData* pDstCol = taosArrayGet(pBlock->pDataBlock, dstSlotId);
591,924✔
897
    if (NULL == pDstCol) {
591,924✔
898
      return terrno;
×
899
    }
900
    colDataSetNULL(pDstCol, rowIndex);
591,924✔
901
  }
902

903
  return TSDB_CODE_SUCCESS;
354,880✔
904
}
905

906
int32_t setSelectivityValue(SqlFunctionCtx* pCtx, SSDataBlock* pBlock, const STuplePos* pTuplePos, int32_t rowIndex) {
2,147,483,647✔
907
  if (pCtx->subsidiaries.num <= 0) {
2,147,483,647✔
908
    return TSDB_CODE_SUCCESS;
2,147,483,647✔
909
  }
910

911
  if ((pCtx->saveHandle.pBuf != NULL && pTuplePos->pageId != -1) ||
75,989,305✔
912
      (pCtx->saveHandle.pState && pTuplePos->streamTupleKey.ts > 0)) {
441✔
913
    int32_t numOfCols = pCtx->subsidiaries.num;
75,989,305✔
914
    char*   p = NULL;
75,989,305✔
915
    int32_t code = loadTupleData(pCtx, pTuplePos, &p);
75,989,305✔
916
    if (p == NULL || TSDB_CODE_SUCCESS != code) {
75,988,248✔
917
      qError("Load tuple data failed since %s, groupId:%" PRIu64 ", ts:%" PRId64, terrstr(),
441✔
918
             pTuplePos->streamTupleKey.groupId, pTuplePos->streamTupleKey.ts);
919
      return TSDB_CODE_NOT_FOUND;
×
920
    }
921

922
    bool* nullList = (bool*)p;
75,987,807✔
923
    char* pStart = (char*)(nullList + numOfCols * sizeof(bool));
75,987,807✔
924

925
    // todo set the offset value to optimize the performance.
926
    for (int32_t j = 0; j < numOfCols; ++j) {
247,200,779✔
927
      SqlFunctionCtx* pc = pCtx->subsidiaries.pCtx[j];
171,211,474✔
928
      int32_t         dstSlotId = pc->pExpr->base.resSchema.slotId;
171,210,834✔
929

930
      SColumnInfoData* pDstCol = taosArrayGet(pBlock->pDataBlock, dstSlotId);
171,210,834✔
931
      if (NULL == pDstCol) {
171,212,114✔
932
        return terrno;
×
933
      }
934
      if (nullList[j]) {
171,212,114✔
935
        colDataSetNULL(pDstCol, rowIndex);
54,780,537✔
936
      } else {
937
        code = colDataSetValOrCover(pDstCol, rowIndex, pStart, false);
116,431,136✔
938
        if (TSDB_CODE_SUCCESS != code) {
116,432,193✔
939
          return code;
×
940
        }
941
      }
942
      pStart += pDstCol->info.bytes;
171,212,730✔
943
    }
944
  }
945

946
  return TSDB_CODE_SUCCESS;
75,989,305✔
947
}
948

949
// This function append the selectivity to subsidiaries function context directly, without fetching data
950
// from intermediate disk based buf page
951
int32_t appendSelectivityValue(SqlFunctionCtx* pCtx, int32_t rowIndex, int32_t pos) {
1,001,576✔
952
  if (pCtx->subsidiaries.num <= 0) {
1,001,576✔
953
    return TSDB_CODE_SUCCESS;
×
954
  }
955

956
  int32_t code = TSDB_CODE_SUCCESS;
1,001,576✔
957
  for (int32_t j = 0; j < pCtx->subsidiaries.num; ++j) {
2,270,062✔
958
    SqlFunctionCtx* pc = pCtx->subsidiaries.pCtx[j];
1,268,486✔
959

960
    // get data from source col
961
    SFunctParam* pFuncParam = &pc->pExpr->base.pParam[0];
1,268,486✔
962
    int32_t      srcSlotId = pFuncParam->pCol->slotId;
1,268,486✔
963

964
    SColumnInfoData* pSrcCol = taosArrayGet(pCtx->pSrcBlock->pDataBlock, srcSlotId);
1,268,486✔
965
    if (NULL == pSrcCol) {
1,268,486✔
966
      return TSDB_CODE_OUT_OF_RANGE;
×
967
    }
968

969
    char* pData = colDataGetData(pSrcCol, rowIndex);
1,268,486✔
970

971
    // append to dest col
972
    int32_t dstSlotId = pc->pExpr->base.resSchema.slotId;
1,268,486✔
973

974
    SColumnInfoData* pDstCol = taosArrayGet(pCtx->pDstBlock->pDataBlock, dstSlotId);
1,268,486✔
975
    if (NULL == pDstCol) {
1,268,486✔
976
      return TSDB_CODE_OUT_OF_RANGE;
×
977
    }
978

979
    if (colDataIsNull_s(pSrcCol, rowIndex) == true) {
2,536,972✔
980
      colDataSetNULL(pDstCol, pos);
52,796✔
981
    } else {
982
      code = colDataSetVal(pDstCol, pos, pData, false);
1,215,690✔
983
      if (TSDB_CODE_SUCCESS != code) {
1,215,690✔
984
        return code;
×
985
      }
986
    }
987
  }
988
  return code;
1,001,576✔
989
}
990

991
void replaceTupleData(STuplePos* pDestPos, STuplePos* pSourcePos) { *pDestPos = *pSourcePos; }
×
992

993
#define COMPARE_MINMAX_DATA(type) (((*(type*)&pDBuf->v) < (*(type*)&pSBuf->v)) ^ isMinFunc)
994
int32_t minMaxCombine(SqlFunctionCtx* pDestCtx, SqlFunctionCtx* pSourceCtx, int32_t isMinFunc) {
×
995
  SResultRowEntryInfo* pDResInfo = GET_RES_INFO(pDestCtx);
×
996
  SMinmaxResInfo*      pDBuf = GET_ROWCELL_INTERBUF(pDResInfo);
×
997

998
  SResultRowEntryInfo* pSResInfo = GET_RES_INFO(pSourceCtx);
×
999
  SMinmaxResInfo*      pSBuf = GET_ROWCELL_INTERBUF(pSResInfo);
×
1000
  int16_t              type = pDBuf->type == TSDB_DATA_TYPE_NULL ? pSBuf->type : pDBuf->type;
×
1001

1002
  switch (type) {
×
1003
    case TSDB_DATA_TYPE_UBIGINT:
×
1004
    case TSDB_DATA_TYPE_BIGINT:
1005
    case TSDB_DATA_TYPE_TIMESTAMP:
1006
      if (pSBuf->assign && (COMPARE_MINMAX_DATA(int64_t) || !pDBuf->assign)) {
×
1007
        pDBuf->v = pSBuf->v;
×
1008
        replaceTupleData(&pDBuf->tuplePos, &pSBuf->tuplePos);
×
1009
        pDBuf->assign = true;
×
1010
      }
1011
      break;
×
1012
    case TSDB_DATA_TYPE_UINT:
×
1013
    case TSDB_DATA_TYPE_INT:
1014
      if (pSBuf->assign && (COMPARE_MINMAX_DATA(int32_t) || !pDBuf->assign)) {
×
1015
        pDBuf->v = pSBuf->v;
×
1016
        replaceTupleData(&pDBuf->tuplePos, &pSBuf->tuplePos);
×
1017
        pDBuf->assign = true;
×
1018
      }
1019
      break;
×
1020
    case TSDB_DATA_TYPE_USMALLINT:
×
1021
    case TSDB_DATA_TYPE_SMALLINT:
1022
      if (pSBuf->assign && (COMPARE_MINMAX_DATA(int16_t) || !pDBuf->assign)) {
×
1023
        pDBuf->v = pSBuf->v;
×
1024
        replaceTupleData(&pDBuf->tuplePos, &pSBuf->tuplePos);
×
1025
        pDBuf->assign = true;
×
1026
      }
1027
      break;
×
1028
    case TSDB_DATA_TYPE_BOOL:
×
1029
    case TSDB_DATA_TYPE_UTINYINT:
1030
    case TSDB_DATA_TYPE_TINYINT:
1031
      if (pSBuf->assign && (COMPARE_MINMAX_DATA(int8_t) || !pDBuf->assign)) {
×
1032
        pDBuf->v = pSBuf->v;
×
1033
        replaceTupleData(&pDBuf->tuplePos, &pSBuf->tuplePos);
×
1034
        pDBuf->assign = true;
×
1035
      }
1036
      break;
×
1037
    case TSDB_DATA_TYPE_DOUBLE:
×
1038
    case TSDB_DATA_TYPE_FLOAT: {
1039
      if (pSBuf->assign && (COMPARE_MINMAX_DATA(double) || !pDBuf->assign)) {
×
1040
        pDBuf->v = pSBuf->v;
×
1041
        replaceTupleData(&pDBuf->tuplePos, &pSBuf->tuplePos);
×
1042
        pDBuf->assign = true;
×
1043
      }
1044
      break;
×
1045
    }
1046
    case TSDB_DATA_TYPE_DECIMAL64: {
×
1047
      const SDecimalOps* pOps = getDecimalOps(type);
×
1048
      if (pSBuf->assign &&
×
1049
          ((pOps->lt(&pDBuf->v, &pSBuf->v, DECIMAL_WORD_NUM(Decimal64)) ^ isMinFunc) || !pDBuf->assign)) {
×
1050
        pDBuf->v = pSBuf->v;
×
1051
        replaceTupleData(&pDBuf->tuplePos, &pSBuf->tuplePos);
×
1052
        pDBuf->assign = true;
×
1053
      }
1054
    } break;
×
1055
    case TSDB_DATA_TYPE_DECIMAL: {
×
1056
      const SDecimalOps* pOps = getDecimalOps(type);
×
1057
      if (pSBuf->assign && (pOps->lt(pDBuf->dec, pSBuf->dec, DECIMAL_WORD_NUM(Decimal)) ^ isMinFunc) ||
×
1058
          !pDBuf->assign) {
×
1059
        memcpy(pDBuf->dec, pSBuf->dec, DECIMAL128_BYTES);
×
1060
        replaceTupleData(&pDBuf->tuplePos, &pSBuf->tuplePos);
×
1061
        pDBuf->assign = true;
×
1062
      }
1063
    } break;
×
1064
    default:
×
1065
      if (pSBuf->assign && (strcmp(pDBuf->str, pSBuf->str) || !pDBuf->assign)) {
×
1066
        memcpy(pDBuf->str, pSBuf->str, varDataLen(pSBuf->str));
×
1067
        replaceTupleData(&pDBuf->tuplePos, &pSBuf->tuplePos);
×
1068
        pDBuf->assign = true;
×
1069
      }
1070
      break;
×
1071
  }
1072
  pDResInfo->numOfRes = TMAX(pDResInfo->numOfRes, pSResInfo->numOfRes);
×
1073
  pDResInfo->isNullRes &= pSResInfo->isNullRes;
×
1074
  return TSDB_CODE_SUCCESS;
×
1075
}
1076

1077
int32_t minCombine(SqlFunctionCtx* pDestCtx, SqlFunctionCtx* pSourceCtx) {
×
1078
  return minMaxCombine(pDestCtx, pSourceCtx, 1);
×
1079
}
1080
int32_t maxCombine(SqlFunctionCtx* pDestCtx, SqlFunctionCtx* pSourceCtx) {
×
1081
  return minMaxCombine(pDestCtx, pSourceCtx, 0);
×
1082
}
1083

1084
int32_t getStdInfoSize() { return (int32_t)sizeof(SStdRes); }
17,558,480✔
1085

1086
bool getStdFuncEnv(SFunctionNode* pFunc, SFuncExecEnv* pEnv) {
3,981,177✔
1087
  pEnv->calcMemSize = sizeof(SStdRes);
3,981,177✔
1088
  return true;
3,981,876✔
1089
}
1090

1091
int32_t stdFunctionSetup(SqlFunctionCtx* pCtx, SResultRowEntryInfo* pResultInfo) {
548,809,707✔
1092
  if (pResultInfo->initialized) {
548,809,707✔
1093
    return TSDB_CODE_SUCCESS;
×
1094
  }
1095
  if (TSDB_CODE_SUCCESS != functionSetup(pCtx, pResultInfo)) {
548,810,793✔
1096
    return TSDB_CODE_FUNC_SETUP_ERROR;
×
1097
  }
1098

1099
  SStdRes* pRes = GET_ROWCELL_INTERBUF(pResultInfo);
548,809,164✔
1100
  (void)memset(pRes, 0, sizeof(SStdRes));
548,808,621✔
1101
  return TSDB_CODE_SUCCESS;
548,808,621✔
1102
}
1103

1104
int32_t stdFunction(SqlFunctionCtx* pCtx) {
1,398,449,983✔
1105
  int32_t numOfElem = 0;
1,398,449,983✔
1106

1107
  // Only the pre-computing information loaded and actual data does not loaded
1108
  SInputColumnInfoData* pInput = &pCtx->input;
1,398,449,983✔
1109
  int32_t               type = pInput->pData[0]->info.type;
1,398,451,531✔
1110

1111
  SStdRes* pStdRes = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
1,398,456,437✔
1112
  pStdRes->type = type;
1,398,450,515✔
1113

1114
  // computing based on the true data block
1115
  SColumnInfoData* pCol = pInput->pData[0];
1,398,450,979✔
1116

1117
  int32_t start = pInput->startRowIndex;
1,398,442,727✔
1118
  int32_t numOfRows = pInput->numOfRows;
1,398,444,297✔
1119

1120
  if (IS_NULL_TYPE(type)) {
1,398,451,647✔
1121
    numOfElem = 0;
81,662✔
1122
    goto _stddev_over;
81,662✔
1123
  }
1124

1125
  switch (type) {
1,398,369,985✔
1126
    case TSDB_DATA_TYPE_TINYINT: {
11,826,083✔
1127
      int8_t* plist = (int8_t*)pCol->pData;
11,826,083✔
1128
      for (int32_t i = start; i < numOfRows + start; ++i) {
2,105,006,499✔
1129
        if (pCol->hasNull && colDataIsNull_f(pCol, i)) {
2,094,106,917✔
1130
          continue;
1,447,509,527✔
1131
        }
1132

1133
        numOfElem += 1;
646,616,466✔
1134
        pStdRes->count += 1;
646,616,466✔
1135
        double nr = (double)plist[i];
652,468,206✔
1136
        if (pStdRes->count == 1) {
652,476,292✔
1137
          pStdRes->dsum = nr;
578,372✔
1138
        } else {
1139
          double          s_kminusone = pStdRes->dsum;
651,924,107✔
1140
          volatile double diff = nr - s_kminusone;
651,905,429✔
1141
          pStdRes->dsum = s_kminusone + diff / (double)pStdRes->count;
651,905,429✔
1142
          pStdRes->quadraticDSum += diff * (nr - pStdRes->dsum);
651,937,827✔
1143
        }
1144
      }
1145

1146
      break;
10,899,582✔
1147
    }
1148

1149
    case TSDB_DATA_TYPE_SMALLINT: {
1,299,450,964✔
1150
      int16_t* plist = (int16_t*)pCol->pData;
1,299,450,964✔
1151
      for (int32_t i = start; i < numOfRows + pInput->startRowIndex; ++i) {
2,147,483,647✔
1152
        if (pCol->hasNull && colDataIsNull_f(pCol, i)) {
2,147,483,647✔
1153
          continue;
2,147,483,647✔
1154
        }
1155

1156
        numOfElem += 1;
1,292,114,214✔
1157
        pStdRes->count += 1;
1,292,114,214✔
1158
        double nr = (double)plist[i];
1,298,906,409✔
1159
        if (pStdRes->count == 1) {
1,298,908,311✔
1160
          pStdRes->dsum = nr;
423,135,361✔
1161
        } else {
1162
          double          s_kminusone = pStdRes->dsum;
875,780,459✔
1163
          volatile double diff = nr - s_kminusone;
875,777,340✔
1164
          pStdRes->dsum = s_kminusone + diff / (double)pStdRes->count;
875,777,340✔
1165
          pStdRes->quadraticDSum += diff * (nr - pStdRes->dsum);
875,763,611✔
1166
        }
1167
      }
1168
      break;
1,299,450,342✔
1169
    }
1170

1171
    case TSDB_DATA_TYPE_INT: {
16,360,580✔
1172
      int32_t* plist = (int32_t*)pCol->pData;
16,360,580✔
1173
      for (int32_t i = start; i < numOfRows + pInput->startRowIndex; ++i) {
2,147,483,647✔
1174
        if (pCol->hasNull && colDataIsNull_f(pCol, i)) {
2,147,483,647✔
1175
          continue;
756,461,603✔
1176
        }
1177

1178
        numOfElem += 1;
2,147,483,647✔
1179
        pStdRes->count += 1;
2,147,483,647✔
1180
        double nr = (double)plist[i];
2,147,483,647✔
1181
        if (pStdRes->count == 1) {
2,147,483,647✔
1182
          pStdRes->dsum = nr;
9,847,168✔
1183
        } else {
1184
          double          s_kminusone = pStdRes->dsum;
2,147,483,647✔
1185
          volatile double diff = nr - s_kminusone;
2,147,483,647✔
1186
          pStdRes->dsum = s_kminusone + diff / (double)pStdRes->count;
2,147,483,647✔
1187
          pStdRes->quadraticDSum += diff * (nr - pStdRes->dsum);
2,147,483,647✔
1188
        }
1189
      }
1190

1191
      break;
16,359,336✔
1192
    }
1193

1194
    case TSDB_DATA_TYPE_BIGINT: {
13,023,566✔
1195
      int64_t* plist = (int64_t*)pCol->pData;
13,023,566✔
1196
      for (int32_t i = start; i < numOfRows + pInput->startRowIndex; ++i) {
2,147,483,647✔
1197
        if (pCol->hasNull && colDataIsNull_f(pCol, i)) {
2,147,483,647✔
1198
          continue;
1,314,502,235✔
1199
        }
1200

1201
        numOfElem += 1;
863,569,285✔
1202
        pStdRes->count += 1;
863,569,285✔
1203
        double nr = (double)plist[i];
871,268,676✔
1204
        if (pStdRes->count == 1) {
871,278,505✔
1205
          pStdRes->dsum = nr;
2,307,805✔
1206
        } else {
1207
          double          s_kminusone = pStdRes->dsum;
868,986,540✔
1208
          volatile double diff = nr - s_kminusone;
868,947,249✔
1209
          pStdRes->dsum = s_kminusone + diff / (double)pStdRes->count;
868,947,249✔
1210
          pStdRes->quadraticDSum += diff * (nr - pStdRes->dsum);
868,994,434✔
1211
        }
1212
      }
1213
      break;
13,027,446✔
1214
    }
1215

1216
    case TSDB_DATA_TYPE_UTINYINT: {
12,846,236✔
1217
      uint8_t* plist = (uint8_t*)pCol->pData;
12,846,236✔
1218
      for (int32_t i = start; i < numOfRows + start; ++i) {
2,147,483,647✔
1219
        if (pCol->hasNull && colDataIsNull_f(pCol, i)) {
2,147,483,647✔
1220
          continue;
1,558,339,094✔
1221
        }
1222

1223
        numOfElem += 1;
1,018,480,124✔
1224
        pStdRes->count += 1;
1,018,480,124✔
1225
        double nr = (double)plist[i];
1,019,706,222✔
1226
        if (pStdRes->count == 1) {
1,019,596,311✔
1227
          pStdRes->dsum = nr;
74,369✔
1228
        } else {
1229
          double          s_kminusone = pStdRes->dsum;
1,019,659,960✔
1230
          volatile double diff = nr - s_kminusone;
1,019,672,535✔
1231
          pStdRes->dsum = s_kminusone + diff / (double)pStdRes->count;
1,019,672,535✔
1232
          pStdRes->quadraticDSum += diff * (nr - pStdRes->dsum);
1,019,666,820✔
1233
        }
1234
      }
1235

1236
      break;
13,520,878✔
1237
    }
1238

1239
    case TSDB_DATA_TYPE_USMALLINT: {
10,343,019✔
1240
      uint16_t* plist = (uint16_t*)pCol->pData;
10,343,019✔
1241
      for (int32_t i = start; i < numOfRows + pInput->startRowIndex; ++i) {
2,084,734,670✔
1242
        if (pCol->hasNull && colDataIsNull_f(pCol, i)) {
2,074,585,624✔
1243
          continue;
1,560,045,463✔
1244
        }
1245

1246
        numOfElem += 1;
512,385,516✔
1247
        pStdRes->count += 1;
512,385,516✔
1248
        double nr = (double)plist[i];
519,415,198✔
1249
        if (pStdRes->count == 1) {
519,417,686✔
1250
          pStdRes->dsum = nr;
32,684✔
1251
        } else {
1252
          double          s_kminusone = pStdRes->dsum;
519,385,624✔
1253
          volatile double diff = nr - s_kminusone;
519,386,246✔
1254
          pStdRes->dsum = s_kminusone + diff / (double)pStdRes->count;
519,386,246✔
1255
          pStdRes->quadraticDSum += diff * (nr - pStdRes->dsum);
519,380,026✔
1256
        }
1257
      }
1258
      break;
10,343,019✔
1259
    }
1260

1261
    case TSDB_DATA_TYPE_UINT: {
5,644,800✔
1262
      uint32_t* plist = (uint32_t*)pCol->pData;
5,644,800✔
1263
      for (int32_t i = start; i < numOfRows + pInput->startRowIndex; ++i) {
1,144,798,989✔
1264
        if (pCol->hasNull && colDataIsNull_f(pCol, i)) {
1,139,180,998✔
1265
          continue;
811,094,553✔
1266
        }
1267

1268
        numOfElem += 1;
327,498,872✔
1269
        pStdRes->count += 1;
327,498,872✔
1270
        double nr = (double)plist[i];
331,354,502✔
1271
        if (pStdRes->count == 1) {
331,348,282✔
1272
          pStdRes->dsum = nr;
23,831✔
1273
        } else {
1274
          double          s_kminusone = pStdRes->dsum;
331,353,063✔
1275
          volatile double diff = nr - s_kminusone;
331,342,489✔
1276
          pStdRes->dsum = s_kminusone + diff / (double)pStdRes->count;
331,342,489✔
1277
          pStdRes->quadraticDSum += diff * (nr - pStdRes->dsum);
331,352,441✔
1278
        }
1279
      }
1280

1281
      break;
5,644,800✔
1282
    }
1283

1284
    case TSDB_DATA_TYPE_UBIGINT: {
5,644,422✔
1285
      uint64_t* plist = (uint64_t*)pCol->pData;
5,644,422✔
1286
      for (int32_t i = start; i < numOfRows + pInput->startRowIndex; ++i) {
1,144,820,543✔
1287
        if (pCol->hasNull && colDataIsNull_f(pCol, i)) {
1,139,253,186✔
1288
          continue;
873,063,798✔
1289
        }
1290

1291
        numOfElem += 1;
266,212,932✔
1292
        pStdRes->count += 1;
266,212,932✔
1293
        double nr = (double)plist[i];
268,687,558✔
1294
        if (pStdRes->count == 1) {
268,688,189✔
1295
          pStdRes->dsum = nr;
20,956✔
1296
        } else {
1297
          double          s_kminusone = pStdRes->dsum;
268,669,757✔
1298
          volatile double diff = nr - s_kminusone;
268,663,456✔
1299
          pStdRes->dsum = s_kminusone + diff / (double)pStdRes->count;
268,663,456✔
1300
          pStdRes->quadraticDSum += diff * (nr - pStdRes->dsum);
268,656,073✔
1301
        }
1302
      }
1303
      break;
5,644,422✔
1304
    }
1305

1306
    case TSDB_DATA_TYPE_FLOAT: {
10,472,502✔
1307
      float* plist = (float*)pCol->pData;
10,472,502✔
1308
      for (int32_t i = start; i < numOfRows + pInput->startRowIndex; ++i) {
1,821,559,514✔
1309
        if (pCol->hasNull && colDataIsNull_f(pCol, i)) {
1,811,086,646✔
1310
          continue;
38,616,215✔
1311
        }
1312

1313
        numOfElem += 1;
1,772,466,264✔
1314
        pStdRes->count += 1;
1,772,466,264✔
1315
        double nr = (double)plist[i];
1,772,469,601✔
1316
        if (pStdRes->count == 1) {
1,772,469,113✔
1317
          pStdRes->dsum = nr;
9,405,911✔
1318
        } else {
1319
          double          s_kminusone = pStdRes->dsum;
1,763,063,202✔
1320
          volatile double diff = nr - s_kminusone;
1,763,063,202✔
1321
          pStdRes->dsum = s_kminusone + diff / (double)pStdRes->count;
1,763,063,202✔
1322
          pStdRes->quadraticDSum += diff * (nr - pStdRes->dsum);
1,763,063,812✔
1323
        }
1324
      }
1325
      break;
10,472,502✔
1326
    }
1327

1328
    case TSDB_DATA_TYPE_DOUBLE: {
12,757,813✔
1329
      double* plist = (double*)pCol->pData;
12,757,813✔
1330
      for (int32_t i = start; i < numOfRows + pInput->startRowIndex; ++i) {
327,553,484✔
1331
        if (pCol->hasNull && colDataIsNull_f(pCol, i)) {
314,811,418✔
1332
          continue;
96,453,655✔
1333
        }
1334

1335
        numOfElem += 1;
218,340,387✔
1336
        pStdRes->count += 1;
218,340,387✔
1337
        double nr = (double)plist[i];
218,318,667✔
1338
        if (pStdRes->count == 1) {
218,319,210✔
1339
          pStdRes->dsum = nr;
5,284,632✔
1340
        } else {
1341
          double          s_kminusone = pStdRes->dsum;
213,040,008✔
1342
          volatile double diff = nr - s_kminusone;
213,039,465✔
1343
          pStdRes->dsum = s_kminusone + diff / (double)pStdRes->count;
213,039,465✔
1344
          pStdRes->quadraticDSum += diff * (nr - pStdRes->dsum);
213,038,922✔
1345
        }
1346
      }
1347
      break;
12,760,528✔
1348
    }
1349

1350
    default:
×
1351
      break;
×
1352
  }
1353

1354
_stddev_over:
1,398,204,517✔
1355
  // data in the check operation are all null, not output
1356
  SET_VAL(GET_RES_INFO(pCtx), numOfElem, 1);
1,398,204,517✔
1357
  return TSDB_CODE_SUCCESS;
1,398,441,543✔
1358
}
1359

1360
static void stdTransferInfo(SStdRes* pInput, SStdRes* pOutput) {
16,909,276✔
1361
  if (IS_NULL_TYPE(pInput->type)) {
16,909,276✔
1362
    return;
22,530✔
1363
  }
1364
  pOutput->type = pInput->type;
16,886,746✔
1365
  if (pOutput->count == 0) {
16,886,746✔
1366
    pOutput->quadraticDSum += pInput->quadraticDSum;
16,598,829✔
1367
    pOutput->dsum += pInput->dsum;
16,598,829✔
1368
    pOutput->count = pInput->count;
16,598,829✔
1369
  } else if (pInput->count > 0) {
287,917✔
1370
    double totalCount = pOutput->count + pInput->count;
126,450✔
1371
    double totalSum = pInput->count * pInput->dsum + pOutput->count * pOutput->dsum;
126,450✔
1372
    double mean = totalSum / totalCount;
126,450✔
1373

1374
    /*
1375
    pOutput->quadraticDSum += pInput->quadraticDSum + pInput->count * pInput->dsum * pInput->dsum +
1376
                              pOutput->count * pOutput->dsum * pOutput->dsum - totalSum * mean;
1377
    */
1378

1379
    double diff = pInput->dsum - pOutput->dsum;
126,450✔
1380
    pOutput->quadraticDSum += pInput->quadraticDSum + pInput->count * pOutput->count * (diff * diff) / totalCount;
126,450✔
1381
    pOutput->dsum = mean;
126,450✔
1382
    pOutput->count += pInput->count;
126,450✔
1383
  }
1384
}
1385

1386
int32_t stdFunctionMerge(SqlFunctionCtx* pCtx) {
16,894,582✔
1387
  SInputColumnInfoData* pInput = &pCtx->input;
16,894,582✔
1388
  SColumnInfoData*      pCol = pInput->pData[0];
16,894,582✔
1389

1390
  if (IS_NULL_TYPE(pCol->info.type)) {
16,894,582✔
1391
    SET_VAL(GET_RES_INFO(pCtx), 0, 1);
×
1392
    return TSDB_CODE_SUCCESS;
×
1393
  }
1394

1395
  if (pCol->info.type != TSDB_DATA_TYPE_BINARY) {
16,894,582✔
1396
    return TSDB_CODE_FUNC_FUNTION_PARA_TYPE;
×
1397
  }
1398

1399
  SStdRes* pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
16,894,582✔
1400

1401
  for (int32_t i = pInput->startRowIndex; i < pInput->startRowIndex + pInput->numOfRows; ++i) {
33,803,858✔
1402
    if (colDataIsNull_s(pCol, i)) continue;
33,818,552✔
1403
    char*    data = colDataGetData(pCol, i);
16,909,276✔
1404
    SStdRes* pInputInfo = (SStdRes*)varDataVal(data);
16,909,276✔
1405
    stdTransferInfo(pInputInfo, pInfo);
16,909,276✔
1406
  }
1407

1408
  SET_VAL(GET_RES_INFO(pCtx), 1, 1);
16,894,582✔
1409
  return TSDB_CODE_SUCCESS;
16,894,582✔
1410
}
1411

1412
int32_t stddevFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
508,513,310✔
1413
  SInputColumnInfoData* pInput = &pCtx->input;
508,513,310✔
1414
  SStdRes*              pStddevRes = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
508,513,310✔
1415
  int32_t               type = pStddevRes->type;
508,513,310✔
1416
  double                avg;
1417

1418
  if (pStddevRes->count == 0) {
508,513,310✔
1419
    GET_RES_INFO(pCtx)->numOfRes = 0;
80,985,111✔
1420

1421
    return functionFinalize(pCtx, pBlock);
80,985,111✔
1422
  }
1423

1424
  if (pStddevRes->count == 1) {
427,528,199✔
1425
    pStddevRes->result = 0.0;
302,836,985✔
1426
  } else {
1427
    pStddevRes->result = sqrt(pStddevRes->quadraticDSum / pStddevRes->count);
124,691,214✔
1428
  }
1429

1430
  // check for overflow
1431
  if (isinf(pStddevRes->result) || isnan(pStddevRes->result)) {
427,528,199✔
1432
    GET_RES_INFO(pCtx)->numOfRes = 0;
×
1433
  }
1434

1435
  return functionFinalize(pCtx, pBlock);
427,528,199✔
1436
}
1437

1438
int32_t stdvarFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
6,543,695✔
1439
  SInputColumnInfoData* pInput = &pCtx->input;
6,543,695✔
1440
  SStdRes*              pStdvarRes = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
6,543,695✔
1441
  int32_t               type = pStdvarRes->type;
6,543,695✔
1442
  double                avg;
1443

1444
  if (pStdvarRes->count == 0) {
6,543,695✔
1445
    GET_RES_INFO(pCtx)->numOfRes = 0;
8,442✔
1446
    return functionFinalize(pCtx, pBlock);
8,442✔
1447
  }
1448

1449
  if (pStdvarRes->count == 1) {
6,535,253✔
1450
    pStdvarRes->result = 0.0;
924✔
1451
  } else {
1452
    pStdvarRes->result = pStdvarRes->quadraticDSum / pStdvarRes->count;
6,534,329✔
1453
  }
1454

1455
  // check for overflow
1456
  if (isinf(pStdvarRes->result) || isnan(pStdvarRes->result)) {
6,535,253✔
1457
    GET_RES_INFO(pCtx)->numOfRes = 0;
×
1458
  }
1459

1460
  return functionFinalize(pCtx, pBlock);
6,535,253✔
1461
}
1462

1463
int32_t stdPartialFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
16,912,314✔
1464
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
16,912,314✔
1465
  SStdRes*             pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
16,912,936✔
1466
  int32_t              resultBytes = getStdInfoSize();
16,912,314✔
1467
  char*                res = taosMemoryCalloc(resultBytes + VARSTR_HEADER_SIZE, sizeof(char));
16,912,314✔
1468

1469
  if (NULL == res) {
16,912,314✔
1470
    return terrno;
×
1471
  }
1472
  (void)memcpy(varDataVal(res), pInfo, resultBytes);
16,912,314✔
1473
  varDataSetLen(res, resultBytes);
16,912,314✔
1474

1475
  int32_t          slotId = pCtx->pExpr->base.resSchema.slotId;
16,912,936✔
1476
  SColumnInfoData* pCol = taosArrayGet(pBlock->pDataBlock, slotId);
16,912,936✔
1477
  if (NULL == pCol) {
16,912,314✔
1478
    taosMemoryFree(res);
×
1479
    return TSDB_CODE_OUT_OF_RANGE;
×
1480
  }
1481

1482
  int32_t code = colDataSetVal(pCol, pBlock->info.rows, res, false);
16,912,314✔
1483

1484
  taosMemoryFree(res);
16,912,936✔
1485
  return code;
16,912,314✔
1486
}
1487

1488
int32_t stdCombine(SqlFunctionCtx* pDestCtx, SqlFunctionCtx* pSourceCtx) {
×
1489
  SResultRowEntryInfo* pDResInfo = GET_RES_INFO(pDestCtx);
×
1490
  SStdRes*             pDBuf = GET_ROWCELL_INTERBUF(pDResInfo);
×
1491

1492
  SResultRowEntryInfo* pSResInfo = GET_RES_INFO(pSourceCtx);
×
1493
  SStdRes*             pSBuf = GET_ROWCELL_INTERBUF(pSResInfo);
×
1494
  int16_t              type = pDBuf->type == TSDB_DATA_TYPE_NULL ? pSBuf->type : pDBuf->type;
×
1495

1496
  stdTransferInfo(pSBuf, pDBuf);
×
1497

1498
  pDResInfo->numOfRes = TMAX(pDResInfo->numOfRes, pSResInfo->numOfRes);
×
1499
  pDResInfo->isNullRes &= pSResInfo->isNullRes;
×
1500
  return TSDB_CODE_SUCCESS;
×
1501
}
1502

1503
int32_t stddevsampFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
3,222,923✔
1504
  SInputColumnInfoData* pInput = &pCtx->input;
3,222,923✔
1505
  SStdRes*              pStddevRes = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
3,222,923✔
1506
  double                avg;
1507

1508
  if (pStddevRes->count == 0) {
3,222,923✔
1509
    GET_RES_INFO(pCtx)->numOfRes = 0;
462✔
1510
    return functionFinalize(pCtx, pBlock);
462✔
1511
  }
1512

1513
  if (pStddevRes->count == 1) {
3,222,461✔
1514
    pStddevRes->result = 0.0;
462✔
1515
  } else {
1516
    pStddevRes->result = sqrt(pStddevRes->quadraticDSum / (pStddevRes->count - 1));
3,221,999✔
1517
  }
1518

1519
  // check for overflow
1520
  if (isinf(pStddevRes->result) || isnan(pStddevRes->result)) {
3,222,461✔
1521
    GET_RES_INFO(pCtx)->numOfRes = 0;
×
1522
  }
1523

1524
  return functionFinalize(pCtx, pBlock);
3,222,461✔
1525
}
1526

1527
int32_t stdvarsampFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
3,221,999✔
1528
  SInputColumnInfoData* pInput = &pCtx->input;
3,221,999✔
1529
  SStdRes*              pStddevRes = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
3,221,999✔
1530
  double                avg;
1531

1532
  if (pStddevRes->count == 0) {
3,221,999✔
1533
    GET_RES_INFO(pCtx)->numOfRes = 0;
462✔
1534
    return functionFinalize(pCtx, pBlock);
462✔
1535
  }
1536

1537
  if (pStddevRes->count == 1) {
3,221,537✔
1538
    pStddevRes->result = 0.0;
462✔
1539
  } else {
1540
    pStddevRes->result = pStddevRes->quadraticDSum / (pStddevRes->count - 1);
3,221,075✔
1541
  }
1542

1543
  // check for overflow
1544
  if (isinf(pStddevRes->result) || isnan(pStddevRes->result)) {
3,221,537✔
1545
    GET_RES_INFO(pCtx)->numOfRes = 0;
×
1546
  }
1547

1548
  return functionFinalize(pCtx, pBlock);
3,221,537✔
1549
}
1550

1551
bool gconcatGetFuncEnv(SFunctionNode* pFunc, SFuncExecEnv* pEnv) {
1,423✔
1552
  pEnv->calcMemSize = sizeof(SGconcatRes);
1,423✔
1553
  return true;
1,423✔
1554
}
1555

1556
int32_t gconcatFunctionSetup(SqlFunctionCtx* pCtx, SResultRowEntryInfo* pResultInfo) {
1,423✔
1557
  if (pResultInfo->initialized) {
1,423✔
1558
    return TSDB_CODE_SUCCESS;
×
1559
  }
1560
  if (TSDB_CODE_SUCCESS != functionSetup(pCtx, pResultInfo)) {
1,423✔
1561
    return TSDB_CODE_FUNC_SETUP_ERROR;
×
1562
  }
1563

1564
  SGconcatRes* pRes = GET_ROWCELL_INTERBUF(pResultInfo);
1,423✔
1565
  (void)memset(pRes, 0, sizeof(SGconcatRes));
1,423✔
1566

1567
  // pRes->separator = varDataVal(pCtx->param[0].param.pz);
1568

1569
  int32_t sepParamIdx = pCtx->numOfParams - 1;
1,423✔
1570
  pRes->separator = pCtx->param[sepParamIdx].param.pz;
1,423✔
1571
  pRes->type = pCtx->param[sepParamIdx].param.nType;
1,423✔
1572

1573
  /*
1574
  SInputColumnInfoData* pInput = &pCtx->input;
1575
  int32_t               type = pInput->pData[0]->info.type;
1576

1577
  pRes->nchar = (type == TSDB_DATA_TYPE_NCHAR);
1578
  */
1579

1580
  return TSDB_CODE_SUCCESS;
1,423✔
1581
}
1582

1583
static int32_t gconcatHelper(const char* input, char* output, bool hasNchar, int32_t type, VarDataLenT* dataLen,
18,012✔
1584
                             void* charsetCxt) {
1585
  if (hasNchar && type == TSDB_DATA_TYPE_VARCHAR) {
18,012✔
1586
    TdUcs4* newBuf = taosMemoryCalloc((varDataLen(input) + 1) * TSDB_NCHAR_SIZE, 1);
×
1587
    if (NULL == newBuf) {
×
1588
      return terrno;
×
1589
    }
1590
    int32_t len = varDataLen(input);
×
1591
    bool    ret =
1592
        taosMbsToUcs4(varDataVal(input), len, newBuf, (varDataLen(input) + 1) * TSDB_NCHAR_SIZE, &len, charsetCxt);
×
1593
    if (!ret) {
×
1594
      taosMemoryFree(newBuf);
×
1595
      return TSDB_CODE_SCALAR_CONVERT_ERROR;
×
1596
    }
1597
    (void)memcpy(varDataVal(output) + *dataLen, newBuf, len);
×
1598
    *dataLen += len;
×
1599
    taosMemoryFree(newBuf);
×
1600
  } else {
1601
    (void)memcpy(varDataVal(output) + *dataLen, varDataVal(input), varDataLen(input));
18,012✔
1602
    *dataLen += varDataLen(input);
18,012✔
1603
  }
1604

1605
  return TSDB_CODE_SUCCESS;
18,012✔
1606
}
1607

1608
int32_t gconcatFunction(SqlFunctionCtx* pCtx) {
948✔
1609
  int32_t               code = 0, numOfElem = 0;
948✔
1610
  SInputColumnInfoData* pInput = &pCtx->input;
948✔
1611
  int32_t               rowStart = pInput->startRowIndex;
948✔
1612
  int32_t               numOfRows = pInput->numOfRows;
948✔
1613
  int32_t               numOfCols = pInput->numOfInputCols;
948✔
1614
  SGconcatRes*          pRes = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
948✔
1615
  char*                 sep = pRes->separator;
948✔
1616
  bool                  hasNchar = pRes->nchar;
948✔
1617
  VarDataLenT           dataLen = 0;
948✔
1618
  bool                  prefixSep = false;
948✔
1619

1620
  if (!pRes->result) {
948✔
1621
    pRes->result = taosMemoryCalloc(1, TSDB_MAX_FIELD_LEN);
948✔
1622
    if (!pRes->result) {
948✔
1623
      return terrno;
×
1624
    }
1625

1626
    varDataSetLen(pRes->result, 0);
948✔
1627

1628
    for (int c = 0; c < numOfCols - 1; ++c) {
1,896✔
1629
      SColumnInfoData* pCol = pInput->pData[c];
948✔
1630
      int32_t          type = pCol->info.type;
948✔
1631

1632
      if (TSDB_DATA_TYPE_NCHAR == type) {
948✔
1633
        pRes->nchar = true;
×
1634
      }
1635
    }
1636
  } else {
1637
    dataLen = varDataLen(pRes->result);
×
1638

1639
    prefixSep = true;
×
1640
    /*
1641
    code = gconcatHelper(sep, pRes->result, hasNchar, pRes->type, &dataLen, NULL);
1642
    if (code) {
1643
      goto _over;
1644
    }
1645
    */
1646
  }
1647

1648
  // computing based on the true data block
1649
  char*            buf = pRes->result;
948✔
1650
  SColumnInfoData* pCol = pInput->pData[numOfCols - 1];
948✔
1651

1652
  sep = colDataGetData(pCol, 0);
948✔
1653
  pRes->type = pCol->info.type;
948✔
1654
  for (int r = rowStart; r < rowStart + numOfRows; ++r) {
10,428✔
1655
    if (prefixSep) {
9,480✔
1656
      // concat the separator
1657
      // setup sepatator's charset instead of the default: pRes->charsetCxt
1658

1659
      code = gconcatHelper(sep, buf, hasNchar, pRes->type, &dataLen, NULL);
8,532✔
1660
      if (code) {
8,532✔
1661
        goto _over;
×
1662
      }
1663
    }
1664

1665
    for (int c = 0; c < numOfCols - 1; ++c) {
18,960✔
1666
      SColumnInfoData* pCol = pInput->pData[c];
9,480✔
1667
      int32_t          type = pCol->info.type;
9,480✔
1668

1669
      if (IS_NULL_TYPE(type) || (pCol->hasNull && colDataIsNull_f(pCol, r))) {
9,480✔
1670
        continue;
×
1671
      }
1672

1673
      // concat this row's all columns
1674
      code = gconcatHelper(colDataGetData(pCol, r), buf, hasNchar, pInput->pData[c]->info.type, &dataLen, NULL);
9,480✔
1675
      if (code) {
9,480✔
1676
        goto _over;
×
1677
      }
1678
    }
1679

1680
    prefixSep = true;
9,480✔
1681
  }
1682

1683
  varDataSetLen(buf, dataLen);
948✔
1684
  numOfElem += 1;
948✔
1685

1686
_over:
948✔
1687
  // data in the check operation are all null, not output
1688
  SET_VAL(GET_RES_INFO(pCtx), numOfElem, 1);
948✔
1689
  return code;
948✔
1690
}
1691

1692
int32_t gconcatFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
948✔
1693
  int32_t               code = 0;
948✔
1694
  SInputColumnInfoData* pInput = &pCtx->input;
948✔
1695
  SGconcatRes*          pRes = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
948✔
1696
  int32_t               slotId = pCtx->pExpr->base.resSchema.slotId;
948✔
1697
  SColumnInfoData*      pCol = taosArrayGet(pBlock->pDataBlock, slotId);
948✔
1698

1699
  if (NULL == pCol) {
948✔
1700
    taosMemoryFree(pRes->result);
×
1701
    return TSDB_CODE_OUT_OF_RANGE;
×
1702
  }
1703

1704
  code = colDataSetVal(pCol, pBlock->info.rows, pRes->result, NULL == pRes->result);
948✔
1705

1706
  taosMemoryFree(pRes->result);
948✔
1707

1708
  return code;
948✔
1709
}
1710

1711
bool getLeastSQRFuncEnv(SFunctionNode* pFunc, SFuncExecEnv* pEnv) {
1,120,395✔
1712
  pEnv->calcMemSize = sizeof(SLeastSQRInfo);
1,120,395✔
1713
  return true;
1,120,395✔
1714
}
1715

1716
int32_t leastSQRFunctionSetup(SqlFunctionCtx* pCtx, SResultRowEntryInfo* pResultInfo) {
5,324,188✔
1717
  if (pResultInfo->initialized) {
5,324,188✔
1718
    return TSDB_CODE_SUCCESS;
×
1719
  }
1720
  if (TSDB_CODE_SUCCESS != functionSetup(pCtx, pResultInfo)) {
5,324,731✔
1721
    return TSDB_CODE_FUNC_SETUP_ERROR;
×
1722
  }
1723

1724
  SLeastSQRInfo* pInfo = GET_ROWCELL_INTERBUF(pResultInfo);
5,325,274✔
1725

1726
  GET_TYPED_DATA(pInfo->startVal, double, pCtx->param[1].param.nType, &pCtx->param[1].param.i,
5,324,731✔
1727
                 typeGetTypeModFromCol(pCtx->param[1].pCol));
1728
  GET_TYPED_DATA(pInfo->stepVal, double, pCtx->param[2].param.nType, &pCtx->param[2].param.i,
5,325,274✔
1729
                 typeGetTypeModFromCol(pCtx->param[2].pCol));
1730
  return TSDB_CODE_SUCCESS;
5,323,102✔
1731
}
1732

1733
int32_t leastSQRFunction(SqlFunctionCtx* pCtx) {
6,219,418✔
1734
  int32_t numOfElem = 0;
6,219,418✔
1735

1736
  SInputColumnInfoData* pInput = &pCtx->input;
6,219,418✔
1737
  int32_t               type = pInput->pData[0]->info.type;
6,219,961✔
1738

1739
  SLeastSQRInfo* pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
6,219,961✔
1740

1741
  SColumnInfoData* pCol = pInput->pData[0];
6,219,961✔
1742

1743
  double(*param)[3] = pInfo->matrix;
6,218,875✔
1744
  double x = pInfo->startVal;
6,218,875✔
1745

1746
  int32_t start = pInput->startRowIndex;
6,218,875✔
1747
  int32_t numOfRows = pInput->numOfRows;
6,218,875✔
1748

1749
  switch (type) {
6,217,246✔
1750
    case TSDB_DATA_TYPE_TINYINT: {
441,486✔
1751
      int8_t* plist = (int8_t*)pCol->pData;
441,486✔
1752
      for (int32_t i = start; i < numOfRows + pInput->startRowIndex; ++i) {
19,266,060✔
1753
        if (pCol->hasNull && colDataIsNull_f(pCol, i)) {
18,824,574✔
1754
          continue;
266,140✔
1755
        }
1756
        numOfElem++;
18,558,434✔
1757
        LEASTSQR_CAL(param, x, plist, i, pInfo->stepVal);
18,558,434✔
1758
      }
1759
      break;
441,486✔
1760
    }
1761
    case TSDB_DATA_TYPE_SMALLINT: {
384,380✔
1762
      int16_t* plist = (int16_t*)pCol->pData;
384,380✔
1763
      for (int32_t i = start; i < numOfRows + pInput->startRowIndex; ++i) {
18,990,560✔
1764
        if (pCol->hasNull && colDataIsNull_f(pCol, i)) {
18,606,180✔
1765
          continue;
58,740✔
1766
        }
1767

1768
        numOfElem++;
18,547,440✔
1769
        LEASTSQR_CAL(param, x, plist, i, pInfo->stepVal);
18,547,440✔
1770
      }
1771
      break;
384,380✔
1772
    }
1773

1774
    case TSDB_DATA_TYPE_INT: {
582,888✔
1775
      int32_t* plist = (int32_t*)pCol->pData;
582,888✔
1776
      for (int32_t i = start; i < numOfRows + pInput->startRowIndex; ++i) {
91,478,264✔
1777
        if (pCol->hasNull && colDataIsNull_f(pCol, i)) {
90,895,376✔
1778
          continue;
238,039✔
1779
        }
1780

1781
        numOfElem++;
90,657,337✔
1782
        LEASTSQR_CAL(param, x, plist, i, pInfo->stepVal);
90,657,337✔
1783
      }
1784
      break;
582,888✔
1785
    }
1786

1787
    case TSDB_DATA_TYPE_BIGINT: {
122,380✔
1788
      int64_t* plist = (int64_t*)pCol->pData;
122,380✔
1789
      for (int32_t i = start; i < numOfRows + pInput->startRowIndex; ++i) {
18,577,754✔
1790
        if (pCol->hasNull && colDataIsNull_f(pCol, i)) {
18,455,374✔
1791
          continue;
58,740✔
1792
        }
1793

1794
        numOfElem++;
18,396,634✔
1795
        LEASTSQR_CAL(param, x, plist, i, pInfo->stepVal);
18,396,634✔
1796
      }
1797
      break;
122,380✔
1798
    }
1799

1800
    case TSDB_DATA_TYPE_UTINYINT: {
17,680✔
1801
      uint8_t* plist = (uint8_t*)pCol->pData;
17,680✔
1802
      for (int32_t i = start; i < numOfRows + pInput->startRowIndex; ++i) {
18,257,160✔
1803
        if (pCol->hasNull && colDataIsNull_f(pCol, i)) {
18,239,480✔
1804
          continue;
10,340✔
1805
        }
1806
        numOfElem++;
18,229,140✔
1807
        LEASTSQR_CAL(param, x, plist, i, pInfo->stepVal);
18,229,140✔
1808
      }
1809
      break;
17,680✔
1810
    }
1811
    case TSDB_DATA_TYPE_USMALLINT: {
17,680✔
1812
      uint16_t* plist = (uint16_t*)pCol->pData;
17,680✔
1813
      for (int32_t i = start; i < numOfRows + pInput->startRowIndex; ++i) {
18,257,160✔
1814
        if (pCol->hasNull && colDataIsNull_f(pCol, i)) {
18,239,480✔
1815
          continue;
9,400✔
1816
        }
1817

1818
        numOfElem++;
18,230,080✔
1819
        LEASTSQR_CAL(param, x, plist, i, pInfo->stepVal);
18,230,080✔
1820
      }
1821
      break;
17,680✔
1822
    }
1823

1824
    case TSDB_DATA_TYPE_UINT: {
17,680✔
1825
      uint32_t* plist = (uint32_t*)pCol->pData;
17,680✔
1826
      for (int32_t i = start; i < numOfRows + pInput->startRowIndex; ++i) {
18,257,160✔
1827
        if (pCol->hasNull && colDataIsNull_f(pCol, i)) {
18,239,480✔
1828
          continue;
9,400✔
1829
        }
1830

1831
        numOfElem++;
18,230,080✔
1832
        LEASTSQR_CAL(param, x, plist, i, pInfo->stepVal);
18,230,080✔
1833
      }
1834
      break;
17,680✔
1835
    }
1836

1837
    case TSDB_DATA_TYPE_UBIGINT: {
17,680✔
1838
      uint64_t* plist = (uint64_t*)pCol->pData;
17,680✔
1839
      for (int32_t i = start; i < numOfRows + pInput->startRowIndex; ++i) {
18,257,160✔
1840
        if (pCol->hasNull && colDataIsNull_f(pCol, i)) {
18,239,480✔
1841
          continue;
9,400✔
1842
        }
1843

1844
        numOfElem++;
18,230,080✔
1845
        LEASTSQR_CAL(param, x, plist, i, pInfo->stepVal);
18,230,080✔
1846
      }
1847
      break;
17,680✔
1848
    }
1849

1850
    case TSDB_DATA_TYPE_FLOAT: {
1,561,284✔
1851
      float* plist = (float*)pCol->pData;
1,561,284✔
1852
      for (int32_t i = start; i < numOfRows + pInput->startRowIndex; ++i) {
95,170,003✔
1853
        if (pCol->hasNull && colDataIsNull_f(pCol, i)) {
93,607,633✔
1854
          continue;
74,587,522✔
1855
        }
1856

1857
        numOfElem++;
19,013,052✔
1858
        LEASTSQR_CAL(param, x, plist, i, pInfo->stepVal);
19,013,052✔
1859
      }
1860
      break;
1,561,827✔
1861
    }
1862

1863
    case TSDB_DATA_TYPE_DOUBLE: {
3,054,108✔
1864
      double* plist = (double*)pCol->pData;
3,054,108✔
1865
      for (int32_t i = start; i < numOfRows + pInput->startRowIndex; ++i) {
102,398,671✔
1866
        if (pCol->hasNull && colDataIsNull_f(pCol, i)) {
99,344,020✔
1867
          continue;
271,140✔
1868
        }
1869

1870
        numOfElem++;
99,071,251✔
1871
        LEASTSQR_CAL(param, x, plist, i, pInfo->stepVal);
99,071,251✔
1872
      }
1873
      break;
3,056,280✔
1874
    }
1875
    case TSDB_DATA_TYPE_NULL: {
×
1876
      GET_RES_INFO(pCtx)->isNullRes = 1;
×
1877
      numOfElem = 1;
×
1878
      break;
×
1879
    }
1880

1881
    default:
×
1882
      break;
×
1883
  }
1884

1885
  pInfo->startVal = x;
6,219,961✔
1886
  pInfo->num += numOfElem;
6,218,875✔
1887

1888
  SET_VAL(GET_RES_INFO(pCtx), numOfElem, 1);
6,218,875✔
1889

1890
  return TSDB_CODE_SUCCESS;
6,219,418✔
1891
}
1892

1893
int32_t leastSQRFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
5,324,336✔
1894
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
5,324,336✔
1895
  SLeastSQRInfo*       pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
5,324,336✔
1896
  int32_t              slotId = pCtx->pExpr->base.resSchema.slotId;
5,324,879✔
1897
  SColumnInfoData*     pCol = taosArrayGet(pBlock->pDataBlock, slotId);
5,324,879✔
1898

1899
  if (NULL == pCol) {
5,324,879✔
1900
    return TSDB_CODE_OUT_OF_RANGE;
×
1901
  }
1902
  int32_t currentRow = pBlock->info.rows;
5,324,879✔
1903

1904
  if (0 == pInfo->num) {
5,324,879✔
1905
    colDataSetNULL(pCol, currentRow);
1,414,152✔
1906
    return TSDB_CODE_SUCCESS;
1,414,152✔
1907
  }
1908

1909
  double(*param)[3] = pInfo->matrix;
3,910,727✔
1910

1911
  param[1][1] = (double)pInfo->num;
3,910,727✔
1912
  param[1][0] = param[0][1];
3,910,727✔
1913

1914
  double param00 = param[0][0] - param[1][0] * (param[0][1] / param[1][1]);
3,910,727✔
1915
  double param02 = param[0][2] - param[1][2] * (param[0][1] / param[1][1]);
3,910,727✔
1916

1917
  if (0 == param00) {
3,910,727✔
1918
    colDataSetNULL(pCol, currentRow);
3,246,959✔
1919
    return TSDB_CODE_SUCCESS;
3,246,959✔
1920
  }
1921

1922
  // param[0][1] = 0;
1923
  double param12 = param[1][2] - param02 * (param[1][0] / param00);
663,768✔
1924
  // param[1][0] = 0;
1925
  param02 /= param00;
663,768✔
1926

1927
  param12 /= param[1][1];
663,768✔
1928

1929
  char buf[LEASTSQUARES_BUFF_LENGTH] = {0};
663,768✔
1930
  char slopBuf[64] = {0};
663,768✔
1931
  char interceptBuf[64] = {0};
663,768✔
1932
  int  n = snprintf(slopBuf, 64, "%.6lf", param02);
663,768✔
1933
  if (n > LEASTSQUARES_DOUBLE_ITEM_LENGTH) {
663,768✔
1934
    (void)snprintf(slopBuf, 64, "%." DOUBLE_PRECISION_DIGITS, param02);
940✔
1935
  }
1936
  n = snprintf(interceptBuf, 64, "%.6lf", param12);
663,768✔
1937
  if (n > LEASTSQUARES_DOUBLE_ITEM_LENGTH) {
663,768✔
1938
    (void)snprintf(interceptBuf, 64, "%." DOUBLE_PRECISION_DIGITS, param12);
2,411✔
1939
  }
1940
  size_t len =
663,768✔
1941
      snprintf(varDataVal(buf), sizeof(buf) - VARSTR_HEADER_SIZE, "{slop:%s, intercept:%s}", slopBuf, interceptBuf);
663,768✔
1942
  varDataSetLen(buf, len);
663,768✔
1943

1944
  int32_t code = colDataSetVal(pCol, currentRow, buf, pResInfo->isNullRes);
663,768✔
1945

1946
  return code;
663,768✔
1947
}
1948

1949
int32_t leastSQRCombine(SqlFunctionCtx* pDestCtx, SqlFunctionCtx* pSourceCtx) {
×
1950
  SResultRowEntryInfo* pDResInfo = GET_RES_INFO(pDestCtx);
×
1951
  SLeastSQRInfo*       pDBuf = GET_ROWCELL_INTERBUF(pDResInfo);
×
1952
  int32_t              type = pDestCtx->input.pData[0]->info.type;
×
1953
  double(*pDparam)[3] = pDBuf->matrix;
×
1954

1955
  SResultRowEntryInfo* pSResInfo = GET_RES_INFO(pSourceCtx);
×
1956
  SLeastSQRInfo*       pSBuf = GET_ROWCELL_INTERBUF(pSResInfo);
×
1957
  double(*pSparam)[3] = pSBuf->matrix;
×
1958
  for (int32_t i = 0; i < pSBuf->num; i++) {
×
1959
    pDparam[0][0] += pDBuf->startVal * pDBuf->startVal;
×
1960
    pDparam[0][1] += pDBuf->startVal;
×
1961
    pDBuf->startVal += pDBuf->stepVal;
×
1962
  }
1963
  pDparam[0][2] += pSparam[0][2] + pDBuf->num * pDBuf->stepVal * pSparam[1][2];
×
1964
  pDparam[1][2] += pSparam[1][2];
×
1965
  pDBuf->num += pSBuf->num;
×
1966
  pDResInfo->numOfRes = TMAX(pDResInfo->numOfRes, pSResInfo->numOfRes);
×
1967
  pDResInfo->isNullRes &= pSResInfo->isNullRes;
×
1968
  return TSDB_CODE_SUCCESS;
×
1969
}
1970

1971
bool getPercentileFuncEnv(SFunctionNode* pFunc, SFuncExecEnv* pEnv) {
92,249✔
1972
  pEnv->calcMemSize = sizeof(SPercentileInfo);
92,249✔
1973
  return true;
92,249✔
1974
}
1975

1976
int32_t percentileFunctionSetup(SqlFunctionCtx* pCtx, SResultRowEntryInfo* pResultInfo) {
523,427✔
1977
  if (pResultInfo->initialized) {
523,427✔
1978
    return TSDB_CODE_SUCCESS;
×
1979
  }
1980
  if (TSDB_CODE_SUCCESS != functionSetup(pCtx, pResultInfo)) {
523,427✔
1981
    return TSDB_CODE_FUNC_SETUP_ERROR;
×
1982
  }
1983

1984
  // in the first round, get the min-max value of all involved data
1985
  SPercentileInfo* pInfo = GET_ROWCELL_INTERBUF(pResultInfo);
523,427✔
1986
  SET_DOUBLE_VAL(&pInfo->minval, DBL_MAX);
523,427✔
1987
  SET_DOUBLE_VAL(&pInfo->maxval, -DBL_MAX);
523,427✔
1988
  pInfo->numOfElems = 0;
523,427✔
1989

1990
  return TSDB_CODE_SUCCESS;
523,427✔
1991
}
1992

1993
void percentileFunctionCleanupExt(SqlFunctionCtx* pCtx) {
92,718✔
1994
  if (pCtx == NULL || GET_RES_INFO(pCtx) == NULL || GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx)) == NULL) {
92,718✔
1995
    return;
×
1996
  }
1997
  SPercentileInfo* pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
92,718✔
1998
  if (pInfo->pMemBucket != NULL) {
92,718✔
1999
    tMemBucketDestroy(&(pInfo->pMemBucket));
469✔
2000
    pInfo->pMemBucket = NULL;
469✔
2001
  }
2002
}
2003

2004
int32_t percentileFunction(SqlFunctionCtx* pCtx) {
2,093,294✔
2005
  int32_t              code = TSDB_CODE_SUCCESS;
2,093,294✔
2006
  int32_t              numOfElems = 0;
2,093,294✔
2007
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
2,093,294✔
2008

2009
  SInputColumnInfoData* pInput = &pCtx->input;
2,093,294✔
2010
  SColumnDataAgg*       pAgg = pInput->pColumnDataAgg[0];
2,093,294✔
2011

2012
  SColumnInfoData* pCol = pInput->pData[0];
2,093,294✔
2013
  int32_t          type = pCol->info.type;
2,093,294✔
2014

2015
  SPercentileInfo* pInfo = GET_ROWCELL_INTERBUF(pResInfo);
2,093,294✔
2016
  if (pCtx->scanFlag == MAIN_SCAN && pInfo->stage == 0) {
2,093,294✔
2017
    pInfo->stage += 1;
523,427✔
2018

2019
    // all data are null, set it completed
2020
    if (pInfo->numOfElems == 0) {
523,427✔
2021
      pResInfo->complete = true;
266,031✔
2022
      return TSDB_CODE_SUCCESS;
266,031✔
2023
    } else {
2024
      code = tMemBucketCreate(pCol->info.bytes, type, typeGetTypeModFromColInfo(&pCol->info), pInfo->minval,
257,396✔
2025
                              pInfo->maxval, pCtx->hasWindowOrGroup, &pInfo->pMemBucket, pInfo->numOfElems);
257,396✔
2026
      if (TSDB_CODE_SUCCESS != code) {
257,396✔
2027
        return code;
×
2028
      }
2029
    }
2030
  }
2031

2032
  // the first stage, only acquire the min/max value
2033
  if (pInfo->stage == 0) {
1,827,263✔
2034
    if (pCtx->input.colDataSMAIsSet) {
1,046,647✔
2035
      double tmin = 0.0, tmax = 0.0;
×
2036
      if (IS_SIGNED_NUMERIC_TYPE(type)) {
×
2037
        tmin = (double)GET_INT64_VAL(&pAgg->min);
×
2038
        tmax = (double)GET_INT64_VAL(&pAgg->max);
×
2039
      } else if (IS_FLOAT_TYPE(type)) {
×
2040
        tmin = GET_DOUBLE_VAL(&pAgg->min);
×
2041
        tmax = GET_DOUBLE_VAL(&pAgg->max);
×
2042
      } else if (IS_UNSIGNED_NUMERIC_TYPE(type)) {
×
2043
        tmin = (double)GET_UINT64_VAL(&pAgg->min);
×
2044
        tmax = (double)GET_UINT64_VAL(&pAgg->max);
×
2045
      }
2046

2047
      if (GET_DOUBLE_VAL(&pInfo->minval) > tmin) {
×
2048
        SET_DOUBLE_VAL(&pInfo->minval, tmin);
×
2049
      }
2050

2051
      if (GET_DOUBLE_VAL(&pInfo->maxval) < tmax) {
×
2052
        SET_DOUBLE_VAL(&pInfo->maxval, tmax);
×
2053
      }
2054

2055
      pInfo->numOfElems += (pInput->numOfRows - pAgg->numOfNull);
×
2056
    } else {
2057
      // check the valid data one by one
2058
      int32_t start = pInput->startRowIndex;
1,046,647✔
2059
      for (int32_t i = start; i < pInput->numOfRows + start; ++i) {
18,183,802✔
2060
        if (colDataIsNull_f(pCol, i)) {
17,137,155✔
2061
          continue;
349,554✔
2062
        }
2063

2064
        char* data = colDataGetData(pCol, i);
16,787,601✔
2065

2066
        double v = 0;
16,787,601✔
2067
        GET_TYPED_DATA(v, double, type, data, typeGetTypeModFromColInfo(&pCol->info));
16,787,601✔
2068
        if (v < GET_DOUBLE_VAL(&pInfo->minval)) {
16,787,601✔
2069
          SET_DOUBLE_VAL(&pInfo->minval, v);
285,344✔
2070
        }
2071

2072
        if (v > GET_DOUBLE_VAL(&pInfo->maxval)) {
16,787,601✔
2073
          SET_DOUBLE_VAL(&pInfo->maxval, v);
13,404,077✔
2074
        }
2075

2076
        pInfo->numOfElems += 1;
16,787,601✔
2077
      }
2078
    }
2079
  } else {
2080
    // the second stage, calculate the true percentile value
2081
    int32_t start = pInput->startRowIndex;
780,616✔
2082
    for (int32_t i = start; i < pInput->numOfRows + start; ++i) {
17,540,077✔
2083
      if (colDataIsNull_f(pCol, i)) {
16,759,930✔
2084
        continue;
×
2085
      }
2086

2087
      char* data = colDataGetData(pCol, i);
16,759,930✔
2088
      numOfElems += 1;
16,759,930✔
2089
      code = tMemBucketPut(pInfo->pMemBucket, data, 1);
16,759,930✔
2090
      if (code != TSDB_CODE_SUCCESS) {
16,759,930✔
2091
        tMemBucketDestroy(&(pInfo->pMemBucket));
469✔
2092
        return code;
469✔
2093
      }
2094
    }
2095

2096
    SET_VAL(pResInfo, numOfElems, 1);
780,147✔
2097
  }
2098

2099
  pCtx->needCleanup = true;
1,826,794✔
2100
  return TSDB_CODE_SUCCESS;
1,826,794✔
2101
}
2102

2103
int32_t percentileFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
522,489✔
2104
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
522,489✔
2105
  SPercentileInfo*     ppInfo = (SPercentileInfo*)GET_ROWCELL_INTERBUF(pResInfo);
522,489✔
2106

2107
  int32_t code = 0;
522,489✔
2108
  double  v = 0;
522,489✔
2109

2110
  tMemBucket** pMemBucket = &ppInfo->pMemBucket;
522,489✔
2111
  if ((*pMemBucket) != NULL && (*pMemBucket)->total > 0) {  // check for null
522,489✔
2112
    if (pCtx->numOfParams > 2) {
256,458✔
2113
      char buf[3200] = {0};
2,814✔
2114
      // max length of double num is 317, e.g. use %.6lf to print -1.0e+308, consider the comma and bracket, 3200 is
2115
      // enough.
2116
      size_t len = 1;
2,814✔
2117

2118
      varDataVal(buf)[0] = '[';
2,814✔
2119
      for (int32_t i = 1; i < pCtx->numOfParams; ++i) {
30,954✔
2120
        SVariant* pVal = &pCtx->param[i].param;
28,140✔
2121

2122
        GET_TYPED_DATA(v, double, pVal->nType, &pVal->i, typeGetTypeModFromCol(pCtx->param[i].pCol));
28,140✔
2123

2124
        code = getPercentile((*pMemBucket), v, &ppInfo->result);
28,140✔
2125
        if (code != TSDB_CODE_SUCCESS) {
28,140✔
2126
          goto _fin_error;
×
2127
        }
2128

2129
        if (i == pCtx->numOfParams - 1) {
28,140✔
2130
          len += snprintf(varDataVal(buf) + len, sizeof(buf) - VARSTR_HEADER_SIZE - len, "%.6lf]", ppInfo->result);
2,814✔
2131
        } else {
2132
          len += snprintf(varDataVal(buf) + len, sizeof(buf) - VARSTR_HEADER_SIZE - len, "%.6lf, ", ppInfo->result);
25,326✔
2133
        }
2134
      }
2135

2136
      int32_t          slotId = pCtx->pExpr->base.resSchema.slotId;
2,814✔
2137
      SColumnInfoData* pCol = taosArrayGet(pBlock->pDataBlock, slotId);
2,814✔
2138
      if (NULL == pCol) {
2,814✔
2139
        code = terrno;
×
2140
        goto _fin_error;
×
2141
      }
2142

2143
      varDataSetLen(buf, len);
2,814✔
2144
      code = colDataSetVal(pCol, pBlock->info.rows, buf, false);
2,814✔
2145
      if (code != TSDB_CODE_SUCCESS) {
2,814✔
2146
        goto _fin_error;
×
2147
      }
2148

2149
      tMemBucketDestroy(pMemBucket);
2,814✔
2150
      return TSDB_CODE_SUCCESS;
2,814✔
2151
    } else {
2152
      SVariant* pVal = &pCtx->param[1].param;
253,644✔
2153

2154
      GET_TYPED_DATA(v, double, pVal->nType, &pVal->i, typeGetTypeModFromCol(pCtx->param[1].pCol));
253,644✔
2155

2156
      code = getPercentile((*pMemBucket), v, &ppInfo->result);
253,644✔
2157
      if (code != TSDB_CODE_SUCCESS) {
253,644✔
2158
        goto _fin_error;
×
2159
      }
2160

2161
      tMemBucketDestroy(pMemBucket);
253,644✔
2162
      return functionFinalize(pCtx, pBlock);
253,644✔
2163
    }
2164
  } else {
2165
    return functionFinalize(pCtx, pBlock);
266,031✔
2166
  }
2167

2168
_fin_error:
×
2169

2170
  tMemBucketDestroy(pMemBucket);
×
2171
  return code;
×
2172
}
2173

2174
bool getApercentileFuncEnv(SFunctionNode* pFunc, SFuncExecEnv* pEnv) {
3,370,458✔
2175
  int32_t bytesHist =
3,370,458✔
2176
      (int32_t)(sizeof(SAPercentileInfo) + sizeof(SHistogramInfo) + sizeof(SHistBin) * (MAX_HISTOGRAM_BIN + 1));
2177
  int32_t bytesDigest = (int32_t)(sizeof(SAPercentileInfo) + TDIGEST_SIZE(COMPRESSION));
3,370,458✔
2178
  pEnv->calcMemSize = TMAX(bytesHist, bytesDigest);
3,370,458✔
2179
  return true;
3,370,071✔
2180
}
2181

2182
int32_t getApercentileMaxSize() {
376,164✔
2183
  int32_t bytesHist =
376,164✔
2184
      (int32_t)(sizeof(SAPercentileInfo) + sizeof(SHistogramInfo) + sizeof(SHistBin) * (MAX_HISTOGRAM_BIN + 1));
2185
  int32_t bytesDigest = (int32_t)(sizeof(SAPercentileInfo) + TDIGEST_SIZE(COMPRESSION));
376,164✔
2186
  return TMAX(bytesHist, bytesDigest);
376,164✔
2187
}
2188

2189
static int8_t getApercentileAlgo(char* algoStr) {
3,049,108✔
2190
  int8_t algoType;
2191
  if (strcasecmp(algoStr, "default") == 0) {
3,049,108✔
2192
    algoType = APERCT_ALGO_DEFAULT;
1,523,175✔
2193
  } else if (strcasecmp(algoStr, "t-digest") == 0) {
1,525,933✔
2194
    algoType = APERCT_ALGO_TDIGEST;
1,525,933✔
2195
  } else {
2196
    algoType = APERCT_ALGO_UNKNOWN;
×
2197
  }
2198

2199
  return algoType;
3,049,108✔
2200
}
2201

2202
static void buildHistogramInfo(SAPercentileInfo* pInfo) {
73,274,533✔
2203
  pInfo->pHisto = (SHistogramInfo*)((char*)pInfo + sizeof(SAPercentileInfo));
73,274,533✔
2204
  pInfo->pHisto->elems = (SHistBin*)((char*)pInfo->pHisto + sizeof(SHistogramInfo));
73,275,619✔
2205
}
73,274,533✔
2206

2207
static void buildTDigestInfo(SAPercentileInfo* pInfo) {
3,065,599✔
2208
  pInfo->pTDigest = (TDigest*)((char*)pInfo + sizeof(SAPercentileInfo));
3,065,599✔
2209
}
3,067,228✔
2210

2211
int32_t apercentileFunctionSetup(SqlFunctionCtx* pCtx, SResultRowEntryInfo* pResultInfo) {
23,951,089✔
2212
  if (pResultInfo->initialized) {
23,951,089✔
2213
    return TSDB_CODE_SUCCESS;
×
2214
  }
2215
  if (TSDB_CODE_SUCCESS != functionSetup(pCtx, pResultInfo)) {
23,951,632✔
2216
    return TSDB_CODE_FUNC_SETUP_ERROR;
×
2217
  }
2218

2219
  SAPercentileInfo* pInfo = GET_ROWCELL_INTERBUF(pResultInfo);
23,951,632✔
2220

2221
  SVariant* pVal = &pCtx->param[1].param;
23,951,632✔
2222
  pInfo->percent = 0;
23,952,718✔
2223
  GET_TYPED_DATA(pInfo->percent, double, pVal->nType, &pVal->i, typeGetTypeModFromCol(pCtx->param[1].pCol));
23,952,718✔
2224

2225
  if (pCtx->numOfParams == 2) {
23,951,089✔
2226
    pInfo->algo = APERCT_ALGO_DEFAULT;
20,901,981✔
2227
  } else if (pCtx->numOfParams == 3) {
3,048,565✔
2228
    pInfo->algo = getApercentileAlgo(varDataVal(pCtx->param[2].param.pz));
3,050,737✔
2229
    if (pInfo->algo == APERCT_ALGO_UNKNOWN) {
3,050,737✔
2230
      return TSDB_CODE_FUNC_FUNTION_PARA_VALUE;
×
2231
    }
2232
  }
2233

2234
  char* tmp = (char*)pInfo + sizeof(SAPercentileInfo);
23,950,546✔
2235
  if (pInfo->algo == APERCT_ALGO_TDIGEST) {
23,952,718✔
2236
    pInfo->pTDigest = tdigestNewFrom(tmp, COMPRESSION);
1,527,019✔
2237
  } else {
2238
    buildHistogramInfo(pInfo);
22,425,699✔
2239
    pInfo->pHisto = tHistogramCreateFrom(tmp, MAX_HISTOGRAM_BIN);
22,425,156✔
2240
    qDebug("%s set up histogram, numOfElems:%" PRId64 ", numOfEntry:%d, pHisto:%p, elems:%p", __FUNCTION__,
22,425,699✔
2241
           pInfo->pHisto->numOfElems, pInfo->pHisto->numOfEntries, pInfo->pHisto, pInfo->pHisto->elems);
2242
  }
2243

2244
  return TSDB_CODE_SUCCESS;
23,951,632✔
2245
}
2246

2247
int32_t apercentileFunction(SqlFunctionCtx* pCtx) {
33,375,114✔
2248
  int32_t               numOfElems = 0;
33,375,114✔
2249
  SResultRowEntryInfo*  pResInfo = GET_RES_INFO(pCtx);
33,375,114✔
2250
  SInputColumnInfoData* pInput = &pCtx->input;
33,375,657✔
2251

2252
  SColumnInfoData* pCol = pInput->pData[0];
33,375,657✔
2253
  int32_t          type = pCol->info.type;
33,375,114✔
2254

2255
  SAPercentileInfo* pInfo = GET_ROWCELL_INTERBUF(pResInfo);
33,374,028✔
2256

2257
  int32_t start = pInput->startRowIndex;
33,375,657✔
2258
  if (pInfo->algo == APERCT_ALGO_TDIGEST) {
33,375,657✔
2259
    buildTDigestInfo(pInfo);
1,526,005✔
2260
    tdigestAutoFill(pInfo->pTDigest, COMPRESSION);
1,526,005✔
2261
    for (int32_t i = start; i < pInput->numOfRows + start; ++i) {
79,475,815✔
2262
      if (colDataIsNull_f(pCol, i)) {
77,949,267✔
2263
        continue;
37,142,805✔
2264
      }
2265
      numOfElems += 1;
40,805,919✔
2266
      char* data = colDataGetData(pCol, i);
40,805,919✔
2267

2268
      double  v = 0;  // value
40,803,204✔
2269
      int64_t w = 1;  // weigth
40,803,204✔
2270
      GET_TYPED_DATA(v, double, type, data, typeGetTypeModFromColInfo(&pCol->info));
40,803,204✔
2271
      int32_t code = tdigestAdd(pInfo->pTDigest, v, w);
40,803,204✔
2272
      if (code != TSDB_CODE_SUCCESS) {
40,806,462✔
2273
        return code;
×
2274
      }
2275
    }
2276
  } else {
2277
    // might be a race condition here that pHisto can be overwritten or setup function
2278
    // has not been called, need to relink the buffer pHisto points to.
2279
    buildHistogramInfo(pInfo);
31,849,731✔
2280
    qDebug("%s before add %d elements into histogram, total:%" PRId64 ", numOfEntry:%d, pHisto:%p, elems: %p",
31,849,731✔
2281
           __FUNCTION__, numOfElems, pInfo->pHisto->numOfElems, pInfo->pHisto->numOfEntries, pInfo->pHisto,
2282
           pInfo->pHisto->elems);
2283
    for (int32_t i = start; i < pInput->numOfRows + start; ++i) {
2,147,483,647✔
2284
      if (colDataIsNull_f(pCol, i)) {
2,147,483,647✔
2285
        continue;
1,425,264,880✔
2286
      }
2287
      numOfElems += 1;
887,445,651✔
2288
      char* data = colDataGetData(pCol, i);
887,445,651✔
2289

2290
      double v = 0;
888,214,226✔
2291
      GET_TYPED_DATA(v, double, type, data, typeGetTypeModFromColInfo(&pCol->info));
888,214,226✔
2292
      int32_t code = tHistogramAdd(&pInfo->pHisto, v);
888,227,216✔
2293
      if (code != TSDB_CODE_SUCCESS) {
886,220,512✔
2294
        return code;
×
2295
      }
2296
    }
2297

2298
    qDebug("%s after add %d elements into histogram, total:%" PRId64 ", numOfEntry:%d, pHisto:%p, elems: %p",
31,849,109✔
2299
           __FUNCTION__, numOfElems, pInfo->pHisto->numOfElems, pInfo->pHisto->numOfEntries, pInfo->pHisto,
2300
           pInfo->pHisto->elems);
2301
  }
2302

2303
  SET_VAL(pResInfo, numOfElems, 1);
33,373,485✔
2304
  return TSDB_CODE_SUCCESS;
33,374,028✔
2305
}
2306

2307
static int32_t apercentileTransferInfo(SAPercentileInfo* pInput, SAPercentileInfo* pOutput, bool* hasRes) {
245,182✔
2308
  pOutput->percent = pInput->percent;
245,182✔
2309
  pOutput->algo = pInput->algo;
245,182✔
2310
  if (pOutput->algo == APERCT_ALGO_TDIGEST) {
245,182✔
2311
    buildTDigestInfo(pInput);
14,601✔
2312
    tdigestAutoFill(pInput->pTDigest, COMPRESSION);
14,601✔
2313

2314
    if (pInput->pTDigest->num_centroids == 0 && pInput->pTDigest->num_buffered_pts == 0) {
14,601✔
2315
      return TSDB_CODE_SUCCESS;
471✔
2316
    }
2317

2318
    if (hasRes) {
14,130✔
2319
      *hasRes = true;
14,130✔
2320
    }
2321

2322
    buildTDigestInfo(pOutput);
14,130✔
2323
    TDigest* pTDigest = pOutput->pTDigest;
14,130✔
2324
    tdigestAutoFill(pTDigest, COMPRESSION);
14,130✔
2325

2326
    if (pTDigest->num_centroids <= 0 && pTDigest->num_buffered_pts == 0) {
14,130✔
2327
      (void)memcpy(pTDigest, pInput->pTDigest, (size_t)TDIGEST_SIZE(COMPRESSION));
14,130✔
2328
      tdigestAutoFill(pTDigest, COMPRESSION);
14,130✔
2329
    } else {
2330
      int32_t code = tdigestMerge(pTDigest, pInput->pTDigest);
×
2331
      if (TSDB_CODE_SUCCESS != code) {
×
2332
        return code;
×
2333
      }
2334
    }
2335
  } else {
2336
    buildHistogramInfo(pInput);
230,581✔
2337
    if (pInput->pHisto->numOfElems <= 0) {
230,581✔
2338
      return TSDB_CODE_SUCCESS;
106,838✔
2339
    }
2340

2341
    if (hasRes) {
123,743✔
2342
      *hasRes = true;
123,743✔
2343
    }
2344

2345
    buildHistogramInfo(pOutput);
123,743✔
2346
    SHistogramInfo* pHisto = pOutput->pHisto;
123,743✔
2347

2348
    if (pHisto->numOfElems <= 0) {
123,743✔
2349
      (void)memcpy(pHisto, pInput->pHisto, sizeof(SHistogramInfo) + sizeof(SHistBin) * (MAX_HISTOGRAM_BIN + 1));
110,535✔
2350
      pHisto->elems = (SHistBin*)((char*)pHisto + sizeof(SHistogramInfo));
110,535✔
2351

2352
      qDebug("%s merge histo, total:%" PRId64 ", entry:%d, %p", __FUNCTION__, pHisto->numOfElems, pHisto->numOfEntries,
110,535✔
2353
             pHisto);
2354
    } else {
2355
      pHisto->elems = (SHistBin*)((char*)pHisto + sizeof(SHistogramInfo));
13,208✔
2356
      qDebug("%s input histogram, elem:%" PRId64 ", entry:%d, %p", __FUNCTION__, pHisto->numOfElems,
13,208✔
2357
             pHisto->numOfEntries, pInput->pHisto);
2358

2359
      SHistogramInfo* pRes = NULL;
13,208✔
2360
      int32_t         code = tHistogramMerge(pHisto, pInput->pHisto, MAX_HISTOGRAM_BIN, &pRes);
13,208✔
2361
      if (TSDB_CODE_SUCCESS != code) {
13,208✔
2362
        tHistogramDestroy(&pRes);
×
2363
        return code;
×
2364
      }
2365
      (void)memcpy(pHisto, pRes, sizeof(SHistogramInfo) + sizeof(SHistBin) * MAX_HISTOGRAM_BIN);
13,208✔
2366
      pHisto->elems = (SHistBin*)((char*)pHisto + sizeof(SHistogramInfo));
13,208✔
2367

2368
      qDebug("%s merge histo, total:%" PRId64 ", entry:%d, %p", __FUNCTION__, pHisto->numOfElems, pHisto->numOfEntries,
13,208✔
2369
             pHisto);
2370
      tHistogramDestroy(&pRes);
13,208✔
2371
    }
2372
  }
2373
  return TSDB_CODE_SUCCESS;
137,873✔
2374
}
2375

2376
int32_t apercentileFunctionMerge(SqlFunctionCtx* pCtx) {
243,050✔
2377
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
243,050✔
2378

2379
  SInputColumnInfoData* pInput = &pCtx->input;
243,050✔
2380

2381
  SColumnInfoData* pCol = pInput->pData[0];
243,050✔
2382
  if (pCol->info.type != TSDB_DATA_TYPE_BINARY) {
243,050✔
2383
    return TSDB_CODE_FUNC_FUNTION_PARA_TYPE;
×
2384
  }
2385

2386
  SAPercentileInfo* pInfo = GET_ROWCELL_INTERBUF(pResInfo);
243,050✔
2387

2388
  qDebug("%s total %" PRId64 " rows will merge, %p", __FUNCTION__, pInput->numOfRows, pInfo->pHisto);
243,050✔
2389

2390
  bool    hasRes = false;
243,050✔
2391
  int32_t start = pInput->startRowIndex;
243,050✔
2392
  for (int32_t i = start; i < start + pInput->numOfRows; ++i) {
488,232✔
2393
    char* data = colDataGetData(pCol, i);
245,182✔
2394

2395
    SAPercentileInfo* pInputInfo = (SAPercentileInfo*)varDataVal(data);
245,182✔
2396
    int32_t           code = apercentileTransferInfo(pInputInfo, pInfo, &hasRes);
245,182✔
2397
    if (TSDB_CODE_SUCCESS != code) {
245,182✔
2398
      return code;
×
2399
    }
2400
  }
2401

2402
  if (pInfo->algo != APERCT_ALGO_TDIGEST) {
243,050✔
2403
    buildHistogramInfo(pInfo);
228,449✔
2404
    qDebug("%s after merge, total:%" PRId64 ", numOfEntry:%d, %p", __FUNCTION__, pInfo->pHisto->numOfElems,
228,449✔
2405
           pInfo->pHisto->numOfEntries, pInfo->pHisto);
2406
  }
2407

2408
  SET_VAL(pResInfo, hasRes ? 1 : 0, 1);
243,050✔
2409
  return TSDB_CODE_SUCCESS;
243,050✔
2410
}
2411

2412
int32_t apercentileFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
19,929,365✔
2413
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
19,929,365✔
2414
  SAPercentileInfo*    pInfo = (SAPercentileInfo*)GET_ROWCELL_INTERBUF(pResInfo);
19,929,365✔
2415

2416
  if (pInfo->algo == APERCT_ALGO_TDIGEST) {
19,929,365✔
2417
    buildTDigestInfo(pInfo);
1,511,949✔
2418
    tdigestAutoFill(pInfo->pTDigest, COMPRESSION);
1,511,949✔
2419
    if (pInfo->pTDigest->size > 0) {
1,511,949✔
2420
      pInfo->result = tdigestQuantile(pInfo->pTDigest, pInfo->percent / 100);
1,511,949✔
2421
    } else {  // no need to free
2422
      // setNull(pCtx->pOutput, pCtx->outputType, pCtx->outputBytes);
2423
      return TSDB_CODE_SUCCESS;
×
2424
    }
2425
  } else {
2426
    buildHistogramInfo(pInfo);
18,417,416✔
2427
    if (pInfo->pHisto->numOfElems > 0) {
18,417,416✔
2428
      qDebug("%s get the final res, elements:%" PRId64 ", numOfEntry:%d, pHisto:%p, elems:%p", __FUNCTION__,
8,695,201✔
2429
             pInfo->pHisto->numOfElems, pInfo->pHisto->numOfEntries, pInfo->pHisto, pInfo->pHisto->elems);
2430

2431
      double  ratio[] = {pInfo->percent};
8,695,201✔
2432
      double* res = NULL;
8,695,201✔
2433
      int32_t code = tHistogramUniform(pInfo->pHisto, ratio, 1, &res);
8,695,201✔
2434
      if (TSDB_CODE_SUCCESS != code) {
8,695,201✔
2435
        taosMemoryFree(res);
×
2436
        return code;
×
2437
      }
2438
      pInfo->result = *res;
8,695,201✔
2439
      // memcpy(pCtx->pOutput, res, sizeof(double));
2440
      taosMemoryFree(res);
8,695,201✔
2441
    } else {  // no need to free
2442
      // setNull(pCtx->pOutput, pCtx->outputType, pCtx->outputBytes);
2443
      // return TSDB_CODE_SUCCESS;
2444
      qDebug("%s get the final res, elements:%" PRId64 ", numOfEntry:%d. result is null", __FUNCTION__,
9,722,215✔
2445
             pInfo->pHisto->numOfElems, pInfo->pHisto->numOfEntries);
2446
    }
2447
  }
2448

2449
  return functionFinalize(pCtx, pBlock);
19,929,365✔
2450
}
2451

2452
int32_t apercentilePartialFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
245,182✔
2453
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
245,182✔
2454
  SAPercentileInfo*    pInfo = (SAPercentileInfo*)GET_ROWCELL_INTERBUF(pResInfo);
245,182✔
2455

2456
  int32_t resultBytes = getApercentileMaxSize();
245,182✔
2457
  char*   res = taosMemoryCalloc(resultBytes + VARSTR_HEADER_SIZE, sizeof(char));
245,182✔
2458
  if (NULL == res) {
245,182✔
2459
    return terrno;
×
2460
  }
2461

2462
  if (pInfo->algo == APERCT_ALGO_TDIGEST) {
245,182✔
2463
    (void)memcpy(varDataVal(res), pInfo, resultBytes);
14,601✔
2464
    varDataSetLen(res, resultBytes);
14,601✔
2465
  } else {
2466
    (void)memcpy(varDataVal(res), pInfo, resultBytes);
230,581✔
2467
    varDataSetLen(res, resultBytes);
230,581✔
2468
  }
2469

2470
  int32_t          slotId = pCtx->pExpr->base.resSchema.slotId;
245,182✔
2471
  SColumnInfoData* pCol = taosArrayGet(pBlock->pDataBlock, slotId);
245,182✔
2472
  if (NULL == pCol) {
245,182✔
2473
    taosMemoryFree(res);
×
2474
    return TSDB_CODE_OUT_OF_RANGE;
×
2475
  }
2476

2477
  int32_t code = colDataSetVal(pCol, pBlock->info.rows, res, false);
245,182✔
2478

2479
  taosMemoryFree(res);
245,182✔
2480
  return code;
245,182✔
2481
}
2482

2483
int32_t apercentileCombine(SqlFunctionCtx* pDestCtx, SqlFunctionCtx* pSourceCtx) {
×
2484
  SResultRowEntryInfo* pDResInfo = GET_RES_INFO(pDestCtx);
×
2485
  SAPercentileInfo*    pDBuf = GET_ROWCELL_INTERBUF(pDResInfo);
×
2486

2487
  SResultRowEntryInfo* pSResInfo = GET_RES_INFO(pSourceCtx);
×
2488
  SAPercentileInfo*    pSBuf = GET_ROWCELL_INTERBUF(pSResInfo);
×
2489

2490
  qDebug("%s start to combine apercentile, %p", __FUNCTION__, pDBuf->pHisto);
×
2491

2492
  int32_t code = apercentileTransferInfo(pSBuf, pDBuf, NULL);
×
2493
  if (TSDB_CODE_SUCCESS != code) {
×
2494
    return code;
×
2495
  }
2496
  pDResInfo->numOfRes = TMAX(pDResInfo->numOfRes, pSResInfo->numOfRes);
×
2497
  pDResInfo->isNullRes &= pSResInfo->isNullRes;
×
2498
  return TSDB_CODE_SUCCESS;
×
2499
}
2500

2501
// TODO: change this function when block data info pks changed
2502
static int32_t comparePkDataWithSValue(int8_t pkType, char* pkData, SValue* pVal, int32_t order) {
181,997✔
2503
  char numVal[8] = {0};
181,997✔
2504
  switch (pkType) {
181,997✔
2505
    case TSDB_DATA_TYPE_INT:
28,179✔
2506
      *(int32_t*)numVal = (int32_t)VALUE_GET_TRIVIAL_DATUM(pVal);
28,179✔
2507
      break;
28,179✔
2508
    case TSDB_DATA_TYPE_UINT:
27,608✔
2509
      *(uint32_t*)numVal = (uint32_t)VALUE_GET_TRIVIAL_DATUM(pVal);
27,608✔
2510
      break;
27,608✔
2511
    case TSDB_DATA_TYPE_BIGINT:
35,928✔
2512
      *(int64_t*)numVal = (int64_t)VALUE_GET_TRIVIAL_DATUM(pVal);
35,928✔
2513
      break;
35,928✔
2514
    case TSDB_DATA_TYPE_UBIGINT:
27,608✔
2515
      *(uint64_t*)numVal = (uint64_t)VALUE_GET_TRIVIAL_DATUM(pVal);
27,608✔
2516
      break;
27,608✔
2517
    default:
62,674✔
2518
      break;
62,674✔
2519
  }
2520
  char*         blockData = (IS_NUMERIC_TYPE(pkType)) ? (char*)numVal : (char*)pVal->pData;
181,997✔
2521
  __compar_fn_t fn = getKeyComparFunc(pkType, order);
181,997✔
2522
  return fn(pkData, blockData);
181,997✔
2523
}
2524

2525
EFuncDataRequired firstDynDataReq(void* pRes, SDataBlockInfo* pBlockInfo) {
2,147,483,647✔
2526
  SResultRowEntryInfo* pEntry = (SResultRowEntryInfo*)pRes;
2,147,483,647✔
2527

2528
  // not initialized yet, data is required
2529
  if (pEntry == NULL) {
2,147,483,647✔
2530
    return FUNC_DATA_REQUIRED_DATA_LOAD;
×
2531
  }
2532

2533
  SFirstLastRes* pResult = GET_ROWCELL_INTERBUF(pEntry);
2,147,483,647✔
2534
  if (pResult->hasResult) {
2,147,483,647✔
2535
    if (pResult->pkBytes > 0) {
2,147,483,647✔
2536
      pResult->pkData = pResult->buf + pResult->bytes;
793,216✔
2537
    } else {
2538
      pResult->pkData = NULL;
2,147,483,647✔
2539
    }
2540
    if (pResult->ts < pBlockInfo->window.skey) {
2,147,483,647✔
2541
      return FUNC_DATA_REQUIRED_NOT_LOAD;
3,444,137✔
2542
    } else if (pResult->ts == pBlockInfo->window.skey) {
2,147,483,647✔
2543
      if (NULL == pResult->pkData) {
2,147,483,647✔
2544
        return FUNC_DATA_REQUIRED_NOT_LOAD;
2,147,483,647✔
2545
      }
2546
      if (comparePkDataWithSValue(pResult->pkType, pResult->pkData, pBlockInfo->pks + 0, TSDB_ORDER_ASC) < 0) {
159,140✔
2547
        return FUNC_DATA_REQUIRED_NOT_LOAD;
10,528✔
2548
      }
2549
    }
2550
    return FUNC_DATA_REQUIRED_DATA_LOAD;
344,437✔
2551
  } else {
2552
    return FUNC_DATA_REQUIRED_DATA_LOAD;
2,222,351✔
2553
  }
2554
}
2555

2556
EFuncDataRequired lastDynDataReq(void* pRes, SDataBlockInfo* pBlockInfo) {
28,226,494✔
2557
  SResultRowEntryInfo* pEntry = (SResultRowEntryInfo*)pRes;
28,226,494✔
2558

2559
  // not initialized yet, data is required
2560
  if (pEntry == NULL) {
28,226,494✔
2561
    return FUNC_DATA_REQUIRED_DATA_LOAD;
×
2562
  }
2563

2564
  SFirstLastRes* pResult = GET_ROWCELL_INTERBUF(pEntry);
28,226,494✔
2565
  if (pResult->hasResult) {
28,229,619✔
2566
    if (pResult->pkBytes > 0) {
26,063,434✔
2567
      pResult->pkData = pResult->buf + pResult->bytes;
261,177✔
2568
    } else {
2569
      pResult->pkData = NULL;
25,801,777✔
2570
    }
2571
    if (pResult->ts > pBlockInfo->window.ekey) {
26,063,421✔
2572
      return FUNC_DATA_REQUIRED_NOT_LOAD;
7,684,197✔
2573
    } else if (pResult->ts == pBlockInfo->window.ekey && pResult->pkData) {
18,378,351✔
2574
      if (comparePkDataWithSValue(pResult->pkType, pResult->pkData, pBlockInfo->pks + 1, TSDB_ORDER_DESC) < 0) {
22,857✔
2575
        return FUNC_DATA_REQUIRED_NOT_LOAD;
10,591✔
2576
      }
2577
    }
2578
    return FUNC_DATA_REQUIRED_DATA_LOAD;
18,366,874✔
2579
  } else {
2580
    return FUNC_DATA_REQUIRED_DATA_LOAD;
2,166,161✔
2581
  }
2582
}
2583

2584
// TODO modify it to include primary key bytes
2585
int32_t getFirstLastInfoSize(int32_t resBytes, int32_t pkBytes) { return sizeof(SFirstLastRes) + resBytes + pkBytes; }
1,793,441,111✔
2586

2587
bool getFirstLastFuncEnv(SFunctionNode* pFunc, SFuncExecEnv* pEnv) {
52,195,803✔
2588
  SColumnNode* pNode = (SColumnNode*)nodesListGetNode(pFunc->pParameterList, 0);
52,195,803✔
2589
  // TODO: change SFunctionNode to add pk info
2590
  int32_t pkBytes = (pFunc->hasPk) ? pFunc->pkBytes : 0;
52,200,474✔
2591
  pEnv->calcMemSize = getFirstLastInfoSize(pNode->node.resType.bytes, pkBytes);
52,194,552✔
2592
  return true;
52,196,321✔
2593
}
2594

2595
bool getSelectivityFuncEnv(SFunctionNode* pFunc, SFuncExecEnv* pEnv) {
15,418,344✔
2596
  SColumnNode* pNode = (SColumnNode*)nodesListGetNode(pFunc->pParameterList, 0);
15,418,344✔
2597
  pEnv->calcMemSize = pNode->node.resType.bytes;
15,419,668✔
2598
  return true;
15,419,668✔
2599
}
2600

2601

2602
bool getHasNullFuncEnv(SFunctionNode* pFunc, SFuncExecEnv* pEnv) {
21,178,370✔
2603
  pEnv->calcMemSize = pFunc->node.resType.bytes;
21,178,370✔
2604
  return true;
21,178,370✔
2605
}
2606

2607
bool getGroupKeyFuncEnv(SFunctionNode* pFunc, SFuncExecEnv* pEnv) {
44,598,626✔
2608
  SColumnNode* pNode = (SColumnNode*)nodesListGetNode(pFunc->pParameterList, 0);
44,598,626✔
2609
  pEnv->calcMemSize = sizeof(SGroupKeyInfo) + pNode->node.resType.bytes;
44,598,656✔
2610
  return true;
44,578,393✔
2611
}
2612

2613
static FORCE_INLINE TSKEY getRowPTs(SColumnInfoData* pTsColInfo, int32_t rowIndex) {
2614
  if (pTsColInfo == NULL || pTsColInfo->pData == NULL) {
2,147,483,647✔
2615
    return 0;
×
2616
  }
2617

2618
  return *(TSKEY*)colDataGetData(pTsColInfo, rowIndex);
2,147,483,647✔
2619
}
2620

2621
int32_t firstLastFunctionSetup(SqlFunctionCtx* pCtx, SResultRowEntryInfo* pResInfo) {
2,147,483,647✔
2622
  if (pResInfo->initialized) {
2,147,483,647✔
2623
    return TSDB_CODE_SUCCESS;
×
2624
  }
2625
  if (TSDB_CODE_SUCCESS != functionSetup(pCtx, pResInfo)) {
2,147,483,647✔
2626
    return TSDB_CODE_FUNC_SETUP_ERROR;
×
2627
  }
2628

2629
  SFirstLastRes* pRes = GET_ROWCELL_INTERBUF(pResInfo);
2,147,483,647✔
2630
  pRes->nullTupleSaved = false;
2,147,483,647✔
2631
  pRes->nullTuplePos.pageId = -1;
2,147,483,647✔
2632
  return TSDB_CODE_SUCCESS;
2,147,483,647✔
2633
}
2634

2635
static int32_t prepareBuf(SqlFunctionCtx* pCtx) {
116,575,360✔
2636
  if (pCtx->subsidiaries.rowLen == 0) {
116,575,360✔
2637
    int32_t rowLen = 0;
5,064,579✔
2638
    for (int32_t j = 0; j < pCtx->subsidiaries.num; ++j) {
11,827,336✔
2639
      SqlFunctionCtx* pc = pCtx->subsidiaries.pCtx[j];
6,765,812✔
2640
      rowLen += pc->pExpr->base.resSchema.bytes;
6,766,033✔
2641
    }
2642

2643
    pCtx->subsidiaries.rowLen = rowLen + pCtx->subsidiaries.num * sizeof(bool);
5,064,779✔
2644
    pCtx->subsidiaries.buf = taosMemoryMalloc(pCtx->subsidiaries.rowLen);
5,065,882✔
2645
    if (NULL == pCtx->subsidiaries.buf) {
5,062,450✔
2646
      return terrno;
×
2647
    }
2648
  }
2649
  return TSDB_CODE_SUCCESS;
116,577,031✔
2650
}
2651

2652
static int32_t firstlastSaveTupleData(const SSDataBlock* pSrcBlock, int32_t rowIndex, SqlFunctionCtx* pCtx,
2,147,483,647✔
2653
                                      SFirstLastRes* pInfo, bool noElements) {
2654
  int32_t code = TSDB_CODE_SUCCESS;
2,147,483,647✔
2655

2656
  if (pCtx->subsidiaries.num <= 0) {
2,147,483,647✔
2657
    return TSDB_CODE_SUCCESS;
2,147,483,647✔
2658
  }
2659

2660
  if (!pInfo->hasResult) {
73,836,303✔
2661
    code = saveTupleData(pCtx, rowIndex, pSrcBlock, &pInfo->pos);
60,643,264✔
2662
  } else if (!noElements) {
13,192,862✔
2663
    code = updateTupleData(pCtx, rowIndex, pSrcBlock, &pInfo->pos);
13,179,836✔
2664
  } else {
2665
  }  // dothing
2666

2667
  return code;
73,839,396✔
2668
}
2669

2670
static int32_t doSaveCurrentVal(SqlFunctionCtx* pCtx, int32_t rowIndex, int64_t currentTs, char* pkData, int32_t type,
2,147,483,647✔
2671
                                char* pData) {
2672
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
2,147,483,647✔
2673
  SFirstLastRes*       pInfo = GET_ROWCELL_INTERBUF(pResInfo);
2,147,483,647✔
2674

2675
  if (IS_VAR_DATA_TYPE(type)) {
2,147,483,647✔
2676
    pInfo->bytes = calcStrBytesByType(type, pData);
2,147,483,647✔
2677
    // if (type == TSDB_DATA_TYPE_JSON) {
2678
    //   pInfo->bytes = getJsonValueLen(pData);
2679
    // } else {
2680
    //   pInfo->bytes = varDataTLen(pData);
2681
    // }
2682
  }
2683

2684
  (void)memcpy(pInfo->buf, pData, pInfo->bytes);
2,147,483,647✔
2685
  if (pkData != NULL) {
2,147,483,647✔
2686
    if (IS_VAR_DATA_TYPE(pInfo->pkType)) {
188,323,427✔
2687
      pInfo->pkBytes = calcStrBytesByType(pInfo->pkType, pkData);
62,653,831✔
2688
      // if (pInfo->pkType == TSDB_DATA_TYPE_JSON) {
2689
      //   pInfo->pkBytes = getJsonValueLen(pkData);
2690
      // } else {
2691
      //   pInfo->pkBytes = varDataTLen(pkData);
2692
      // }
2693
    }
2694
    (void)memcpy(pInfo->buf + pInfo->bytes, pkData, pInfo->pkBytes);
188,309,447✔
2695
    pInfo->pkData = pInfo->buf + pInfo->bytes;
188,309,467✔
2696
  }
2697

2698
  pInfo->ts = currentTs;
2,147,483,647✔
2699
  int32_t code = firstlastSaveTupleData(pCtx->pSrcBlock, rowIndex, pCtx, pInfo, false);
2,147,483,647✔
2700
  if (code != TSDB_CODE_SUCCESS) {
2,147,483,647✔
2701
    return code;
×
2702
  }
2703

2704
  pInfo->hasResult = true;
2,147,483,647✔
2705
  return TSDB_CODE_SUCCESS;
2,147,483,647✔
2706
}
2707

2708
// This ordinary first function does not care if current scan is ascending order or descending order scan
2709
// the OPTIMIZED version of first function will only handle the ascending order scan
2710
int32_t firstFunction(SqlFunctionCtx* pCtx) {
2,147,483,647✔
2711
  int32_t numOfElems = 0;
2,147,483,647✔
2712

2713
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
2,147,483,647✔
2714
  SFirstLastRes*       pInfo = GET_ROWCELL_INTERBUF(pResInfo);
2,147,483,647✔
2715

2716
  SInputColumnInfoData* pInput = &pCtx->input;
2,147,483,647✔
2717
  SColumnInfoData*      pInputCol = pInput->pData[0];
2,147,483,647✔
2718

2719
  pInfo->bytes = pInputCol->info.bytes;
2,147,483,647✔
2720

2721
  if (IS_NULL_TYPE(pInputCol->info.type)) {
2,147,483,647✔
2722
    return TSDB_CODE_SUCCESS;
655,378✔
2723
  }
2724

2725
  SColumnInfoData* pkCol = pInput->pPrimaryKey;
2,147,483,647✔
2726
  pInfo->pkType = -1;
2,147,483,647✔
2727
  __compar_fn_t pkCompareFn = NULL;
2,147,483,647✔
2728
  if (pCtx->hasPrimaryKey) {
2,147,483,647✔
2729
    pInfo->pkType = pkCol->info.type;
10,653,150✔
2730
    pInfo->pkBytes = pkCol->info.bytes;
10,655,148✔
2731
    pkCompareFn = getKeyComparFunc(pInfo->pkType, TSDB_ORDER_ASC);
10,654,482✔
2732
  }
2733

2734
  // All null data column, return directly.
2735
  if (pInput->colDataSMAIsSet && (pInput->pColumnDataAgg[0]->numOfNull == pInput->totalRows) &&
2,147,483,647✔
2736
      pInputCol->hasNull == true) {
×
2737
    // save selectivity value for column consisted of all null values
2738
    int32_t code = firstlastSaveTupleData(pCtx->pSrcBlock, pInput->startRowIndex, pCtx, pInfo, true);
×
2739
    if (code != TSDB_CODE_SUCCESS) {
×
2740
      return code;
×
2741
    }
2742
    pInfo->nullTupleSaved = true;
×
2743
    return TSDB_CODE_SUCCESS;
×
2744
  }
2745

2746
  SColumnDataAgg* pColAgg = (pInput->colDataSMAIsSet) ? pInput->pColumnDataAgg[0] : NULL;
2,147,483,647✔
2747

2748
  TSKEY startKey = getRowPTs(pInput->pPTS, 0);
2,147,483,647✔
2749
  TSKEY endKey = getRowPTs(pInput->pPTS, pInput->totalRows - 1);
2,147,483,647✔
2750

2751
  int32_t blockDataOrder = (startKey <= endKey) ? TSDB_ORDER_ASC : TSDB_ORDER_DESC;
2,147,483,647✔
2752

2753
  //  please ref. to the comment in lastRowFunction for the reason why disabling the opt version of last/first
2754
  //  function. we will use this opt implementation in an new version that is only available in scan subplan
2755
#if 0
2756
  if (blockDataOrder == TSDB_ORDER_ASC) {
2757
    // filter according to current result firstly
2758
    if (pResInfo->numOfRes > 0) {
2759
      if (pInfo->ts < startKey) {
2760
        return TSDB_CODE_SUCCESS;
2761
      }
2762
    }
2763

2764
    for (int32_t i = pInput->startRowIndex; i < pInput->startRowIndex + pInput->numOfRows; ++i) {
2765
      if (pInputCol->hasNull && colDataIsNull(pInputCol, pInput->totalRows, i, pColAgg)) {
2766
        continue;
2767
      }
2768

2769
      numOfElems++;
2770

2771
      char* data = colDataGetData(pInputCol, i);
2772
      TSKEY cts = getRowPTs(pInput->pPTS, i);
2773
      if (pResInfo->numOfRes == 0 || pInfo->ts > cts) {
2774
        doSaveCurrentVal(pCtx, i, cts, pInputCol->info.type, data);
2775
        break;
2776
      }
2777
    }
2778
  } else {
2779
    // in case of descending order time stamp serial, which usually happens as the results of the nest query,
2780
    // all data needs to be check.
2781
    if (pResInfo->numOfRes > 0) {
2782
      if (pInfo->ts < endKey) {
2783
        return TSDB_CODE_SUCCESS;
2784
      }
2785
    }
2786

2787
    for (int32_t i = pInput->numOfRows + pInput->startRowIndex - 1; i >= pInput->startRowIndex; --i) {
2788
      if (pInputCol->hasNull && colDataIsNull(pInputCol, pInput->totalRows, i, pColAgg)) {
2789
        continue;
2790
      }
2791

2792
      numOfElems++;
2793

2794
      char* data = colDataGetData(pInputCol, i);
2795
      TSKEY cts = getRowPTs(pInput->pPTS, i);
2796

2797
      if (pResInfo->numOfRes == 0 || pInfo->ts > cts) {
2798
        doSaveCurrentVal(pCtx, i, cts, pInputCol->info.type, data);
2799
        break;
2800
      }
2801
    }
2802
  }
2803
#else
2804
  int64_t* pts = (int64_t*)pInput->pPTS->pData;
2,147,483,647✔
2805

2806
  int     from = -1;
2,147,483,647✔
2807
  int32_t i = -1;
2,147,483,647✔
2808
  while (funcInputGetNextRowIndex(pInput, from, true, &i, &from)) {
2,147,483,647✔
2809
    if (pInputCol->hasNull && colDataIsNull(pInputCol, pInput->totalRows, i, pColAgg)) {
2,147,483,647✔
2810
      continue;
2,147,483,647✔
2811
    }
2812

2813
    numOfElems++;
2,147,483,647✔
2814
    char* data = colDataGetData(pInputCol, i);
2,147,483,647✔
2815
    char* pkData = NULL;
2,147,483,647✔
2816
    if (pCtx->hasPrimaryKey) {
2,147,483,647✔
2817
      pkData = colDataGetData(pkCol, i);
181,752,412✔
2818
    }
2819
    TSKEY cts = pts[i];
2,147,483,647✔
2820
    if (pResInfo->numOfRes == 0 || pInfo->ts > cts ||
2,147,483,647✔
2821
        (pInfo->ts == cts && pkCompareFn && pkCompareFn(pkData, pInfo->pkData) < 0)) {
2,147,483,647✔
2822
      int32_t code = doSaveCurrentVal(pCtx, i, cts, pkData, pInputCol->info.type, data);
2,147,483,647✔
2823
      if (code != TSDB_CODE_SUCCESS) {
2,147,483,647✔
2824
        return code;
×
2825
      }
2826
      pResInfo->numOfRes = 1;
2,147,483,647✔
2827
    }
2828
  }
2829
#endif
2830

2831
  if (numOfElems == 0) {
2,147,483,647✔
2832
    // save selectivity value for column consisted of all null values
2833
    int32_t code = firstlastSaveTupleData(pCtx->pSrcBlock, pInput->startRowIndex, pCtx, pInfo, true);
2,147,483,647✔
2834
    if (code != TSDB_CODE_SUCCESS) {
2,147,483,647✔
2835
      return code;
×
2836
    }
2837
    pInfo->nullTupleSaved = true;
2,147,483,647✔
2838
  }
2839
  SET_VAL(pResInfo, numOfElems, 1);
2,147,483,647✔
2840
  return TSDB_CODE_SUCCESS;
2,147,483,647✔
2841
}
2842

2843
int32_t lastFunction(SqlFunctionCtx* pCtx) {
2,147,483,647✔
2844
  int32_t numOfElems = 0;
2,147,483,647✔
2845

2846
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
2,147,483,647✔
2847
  SFirstLastRes*       pInfo = GET_ROWCELL_INTERBUF(pResInfo);
2,147,483,647✔
2848

2849
  SInputColumnInfoData* pInput = &pCtx->input;
2,147,483,647✔
2850
  SColumnInfoData*      pInputCol = pInput->pData[0];
2,147,483,647✔
2851

2852
  int32_t type = pInputCol->info.type;
2,147,483,647✔
2853
  int32_t bytes = pInputCol->info.bytes;
2,147,483,647✔
2854

2855
  if (IS_NULL_TYPE(type)) {
2,147,483,647✔
2856
    return TSDB_CODE_SUCCESS;
637,351✔
2857
  }
2858
  pInfo->bytes = bytes;
2,147,483,647✔
2859

2860
  SColumnInfoData* pkCol = pInput->pPrimaryKey;
2,147,483,647✔
2861
  pInfo->pkType = -1;
2,147,483,647✔
2862
  __compar_fn_t pkCompareFn = NULL;
2,147,483,647✔
2863
  if (pCtx->hasPrimaryKey) {
2,147,483,647✔
2864
    pInfo->pkType = pkCol->info.type;
10,756,646✔
2865
    pInfo->pkBytes = pkCol->info.bytes;
10,759,268✔
2866
    pkCompareFn = getKeyComparFunc(pInfo->pkType, TSDB_ORDER_DESC);
10,755,976✔
2867
  }
2868

2869
  // All null data column, return directly.
2870
  if (pInput->colDataSMAIsSet && (pInput->pColumnDataAgg[0]->numOfNull == pInput->totalRows) &&
2,147,483,647✔
2871
      pInputCol->hasNull == true) {
×
2872
    // save selectivity value for column consisted of all null values
2873
    int32_t code = firstlastSaveTupleData(pCtx->pSrcBlock, pInput->startRowIndex, pCtx, pInfo, true);
×
2874
    if (code != TSDB_CODE_SUCCESS) {
×
2875
      return code;
×
2876
    }
2877
    pInfo->nullTupleSaved = true;
×
2878
    return TSDB_CODE_SUCCESS;
×
2879
  }
2880

2881
  SColumnDataAgg* pColAgg = (pInput->colDataSMAIsSet) ? pInput->pColumnDataAgg[0] : NULL;
2,147,483,647✔
2882

2883
  TSKEY startKey = getRowPTs(pInput->pPTS, 0);
2,147,483,647✔
2884
  TSKEY endKey = getRowPTs(pInput->pPTS, pInput->totalRows - 1);
2,147,483,647✔
2885

2886
  int32_t blockDataOrder = (startKey <= endKey) ? TSDB_ORDER_ASC : TSDB_ORDER_DESC;
2,147,483,647✔
2887

2888
  //  please ref. to the comment in lastRowFunction for the reason why disabling the opt version of last/first function.
2889
#if 0
2890
  if (blockDataOrder == TSDB_ORDER_ASC) {
2891
    for (int32_t i = pInput->numOfRows + pInput->startRowIndex - 1; i >= pInput->startRowIndex; --i) {
2892
      if (pInputCol->hasNull && colDataIsNull(pInputCol, pInput->totalRows, i, pColAgg)) {
2893
        continue;
2894
      }
2895

2896
      numOfElems++;
2897

2898
      char* data = colDataGetData(pInputCol, i);
2899
      TSKEY cts = getRowPTs(pInput->pPTS, i);
2900
      if (pResInfo->numOfRes == 0 || pInfo->ts < cts) {
2901
        doSaveCurrentVal(pCtx, i, cts, type, data);
2902
      }
2903

2904
      break;
2905
    }
2906
  } else {  // descending order
2907
    for (int32_t i = pInput->startRowIndex; i < pInput->numOfRows + pInput->startRowIndex; ++i) {
2908
      if (pInputCol->hasNull && colDataIsNull(pInputCol, pInput->totalRows, i, pColAgg)) {
2909
        continue;
2910
      }
2911

2912
      numOfElems++;
2913

2914
      char* data = colDataGetData(pInputCol, i);
2915
      TSKEY cts = getRowPTs(pInput->pPTS, i);
2916
      if (pResInfo->numOfRes == 0 || pInfo->ts < cts) {
2917
        doSaveCurrentVal(pCtx, i, cts, type, data);
2918
      }
2919
      break;
2920
    }
2921
  }
2922
#else
2923
  int64_t* pts = (int64_t*)pInput->pPTS->pData;
2,147,483,647✔
2924

2925
#if 0
2926
    for (int32_t i = pInput->startRowIndex; i < pInput->numOfRows + pInput->startRowIndex; ++i) {
2927
      if (pInputCol->hasNull && colDataIsNull(pInputCol, pInput->totalRows, i, pColAgg)) {
2928
        continue;
2929
      }
2930

2931
      numOfElems++;
2932
      if (pResInfo->numOfRes == 0 || pInfo->ts < pts[i]) {
2933
        char* data = colDataGetData(pInputCol, i);
2934
        doSaveCurrentVal(pCtx, i, pts[i], type, data);
2935
        pResInfo->numOfRes = 1;
2936
      }
2937
    }
2938
#else
2939

2940
  // todo refactor
2941
  if (!pInputCol->hasNull && !pCtx->hasPrimaryKey) {
2,147,483,647✔
2942
    numOfElems = 1;
2,147,483,647✔
2943

2944
    int32_t round = pInput->numOfRows >> 2;
2,147,483,647✔
2945
    int32_t reminder = pInput->numOfRows & 0x03;
2,147,483,647✔
2946

2947
    for (int32_t i = pInput->startRowIndex, tick = 0; tick < round; i += 4, tick += 1) {
2,147,483,647✔
2948
      int64_t cts = pts[i];
413,678,621✔
2949
      int32_t chosen = i;
413,684,071✔
2950

2951
      if (cts < pts[i + 1]) {
413,684,071✔
2952
        cts = pts[i + 1];
138,920,581✔
2953
        chosen = i + 1;
138,920,581✔
2954
      }
2955

2956
      if (cts < pts[i + 2]) {
413,680,339✔
2957
        cts = pts[i + 2];
138,920,852✔
2958
        chosen = i + 2;
138,920,852✔
2959
      }
2960

2961
      if (cts < pts[i + 3]) {
413,676,491✔
2962
        cts = pts[i + 3];
138,919,252✔
2963
        chosen = i + 3;
138,919,252✔
2964
      }
2965

2966
      if (pResInfo->numOfRes == 0 || pInfo->ts < cts) {
413,686,294✔
2967
        char*   data = colDataGetData(pInputCol, chosen);
166,830,547✔
2968
        int32_t code = doSaveCurrentVal(pCtx, chosen, cts, NULL, type, data);
166,842,948✔
2969
        if (code != TSDB_CODE_SUCCESS) {
166,838,709✔
2970
          return code;
×
2971
        }
2972
        pResInfo->numOfRes = 1;
166,838,709✔
2973
      }
2974
    }
2975

2976
    for (int32_t i = pInput->startRowIndex + round * 4; i < pInput->startRowIndex + pInput->numOfRows; ++i) {
2,147,483,647✔
2977
      if (pResInfo->numOfRes == 0 || pInfo->ts < pts[i]) {
2,147,483,647✔
2978
        char*   data = colDataGetData(pInputCol, i);
924,201,644✔
2979
        int32_t code = doSaveCurrentVal(pCtx, i, pts[i], NULL, type, data);
920,023,221✔
2980
        if (code != TSDB_CODE_SUCCESS) {
919,648,126✔
2981
          return code;
×
2982
        }
2983
        pResInfo->numOfRes = 1;
919,648,126✔
2984
      }
2985
    }
2986
  } else {
2987
    int     from = -1;
2,147,483,647✔
2988
    int32_t i = -1;
2,147,483,647✔
2989
    while (funcInputGetNextRowIndex(pInput, from, false, &i, &from)) {
2,147,483,647✔
2990
      if (colDataIsNull(pInputCol, pInput->totalRows, i, pColAgg)) {
2,147,483,647✔
2991
        continue;
2,147,483,647✔
2992
      }
2993

2994
      numOfElems++;
2,147,483,647✔
2995
      char* pkData = NULL;
2,147,483,647✔
2996
      if (pCtx->hasPrimaryKey && !colDataIsNull_s(pkCol, i)) {
2,147,483,647✔
2997
        // pkCol[i] might be null when using cachemodel
2998
        // however, if using cachemodel, we don't need pk to determine the order
2999
        // because ts is enough
3000
        pkData = colDataGetData(pkCol, i);
181,445,559✔
3001
      }
3002
      if (pResInfo->numOfRes == 0 || pInfo->ts < pts[i] ||
2,147,483,647✔
3003
          (pInfo->ts == pts[i] && pkCompareFn && pkCompareFn(pkData, pInfo->pkData) < 0)) {
2,147,483,647✔
3004
        char*   data = colDataGetData(pInputCol, i);
2,147,483,647✔
3005
        int32_t code = doSaveCurrentVal(pCtx, i, pts[i], pkData, type, data);
2,147,483,647✔
3006
        if (code != TSDB_CODE_SUCCESS) {
2,147,483,647✔
3007
          return code;
×
3008
        }
3009
        pResInfo->numOfRes = 1;
2,147,483,647✔
3010
      }
3011
    }
3012
  }
3013
#endif
3014

3015
#endif
3016

3017
  // save selectivity value for column consisted of all null values
3018
  if (numOfElems == 0) {
2,147,483,647✔
3019
    int32_t code = firstlastSaveTupleData(pCtx->pSrcBlock, pInput->startRowIndex, pCtx, pInfo, true);
2,147,483,647✔
3020
    if (code != TSDB_CODE_SUCCESS) {
2,147,483,647✔
3021
      return code;
×
3022
    }
3023
    pInfo->nullTupleSaved = true;
2,147,483,647✔
3024
  }
3025

3026
  return TSDB_CODE_SUCCESS;
2,147,483,647✔
3027
}
3028

3029
static bool firstLastTransferInfoImpl(SFirstLastRes* pInput, SFirstLastRes* pOutput, bool isFirst) {
1,386,747,666✔
3030
  if (!pInput->hasResult) {
1,386,747,666✔
3031
    return false;
×
3032
  }
3033
  __compar_fn_t pkCompareFn = NULL;
1,386,747,666✔
3034
  if (pInput->pkData) {
1,386,747,666✔
3035
    pkCompareFn = getKeyComparFunc(pInput->pkType, (isFirst) ? TSDB_ORDER_ASC : TSDB_ORDER_DESC);
4,103,320✔
3036
  }
3037
  if (pOutput->hasResult) {
1,386,748,861✔
3038
    if (isFirst) {
756,747,051✔
3039
      if (pInput->ts > pOutput->ts ||
660,806,187✔
3040
          (pInput->ts == pOutput->ts && pkCompareFn && pkCompareFn(pInput->pkData, pOutput->pkData) > 0)) {
659,872,503✔
3041
        return false;
1,036,128✔
3042
      }
3043
    } else {
3044
      if (pInput->ts < pOutput->ts ||
95,940,864✔
3045
          (pInput->ts == pOutput->ts && pkCompareFn && pkCompareFn(pInput->pkData, pOutput->pkData) > 0)) {
93,816,270✔
3046
        return false;
2,351,154✔
3047
      }
3048
    }
3049
  }
3050

3051
  pOutput->isNull = pInput->isNull;
1,383,361,101✔
3052
  pOutput->ts = pInput->ts;
1,383,361,340✔
3053
  pOutput->bytes = pInput->bytes;
1,383,361,555✔
3054
  pOutput->pkType = pInput->pkType;
1,383,361,579✔
3055

3056
  (void)memcpy(pOutput->buf, pInput->buf, pOutput->bytes);
1,383,360,838✔
3057
  if (pInput->pkData) {
1,383,362,057✔
3058
    pOutput->pkBytes = pInput->pkBytes;
3,647,874✔
3059
    (void)memcpy(pOutput->buf + pOutput->bytes, pInput->pkData, pOutput->pkBytes);
3,647,874✔
3060
    pOutput->pkData = pOutput->buf + pOutput->bytes;
3,647,874✔
3061
  }
3062
  return true;
1,383,364,710✔
3063
}
3064

3065
static int32_t firstLastTransferInfo(SqlFunctionCtx* pCtx, SFirstLastRes* pInput, SFirstLastRes* pOutput, bool isFirst,
1,386,735,238✔
3066
                                     int32_t rowIndex) {
3067
  if (firstLastTransferInfoImpl(pInput, pOutput, isFirst)) {
1,386,735,238✔
3068
    int32_t code = firstlastSaveTupleData(pCtx->pSrcBlock, rowIndex, pCtx, pOutput, false);
1,383,364,710✔
3069
    if (TSDB_CODE_SUCCESS != code) {
1,383,366,646✔
3070
      return code;
×
3071
    }
3072
    pOutput->hasResult = true;
1,383,366,646✔
3073
  }
3074
  return TSDB_CODE_SUCCESS;
1,386,753,928✔
3075
}
3076

3077
static int32_t firstLastFunctionMergeImpl(SqlFunctionCtx* pCtx, bool isFirstQuery) {
643,965,263✔
3078
  SInputColumnInfoData* pInput = &pCtx->input;
643,965,263✔
3079
  SColumnInfoData*      pCol = pInput->pData[0];
643,965,263✔
3080

3081
  if (IS_NULL_TYPE(pCol->info.type)) {
643,965,502✔
3082
    SET_VAL(GET_RES_INFO(pCtx), 0, 1);
×
3083
    return TSDB_CODE_SUCCESS;
×
3084
  }
3085

3086
  if (pCol->info.type != TSDB_DATA_TYPE_BINARY) {
643,965,741✔
3087
    return TSDB_CODE_FUNC_FUNTION_PARA_TYPE;
×
3088
  }
3089

3090
  SFirstLastRes* pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
643,965,980✔
3091

3092
  int32_t start = pInput->startRowIndex;
643,965,956✔
3093
  int32_t numOfElems = 0;
643,965,956✔
3094

3095
  for (int32_t i = start; i < start + pInput->numOfRows; ++i) {
2,147,483,647✔
3096
    if (colDataIsNull_s(pCol, i)) {
2,147,483,647✔
3097
      continue;
236,747,885✔
3098
    }
3099
    char*          data = colDataGetData(pCol, i);
1,386,750,773✔
3100
    SFirstLastRes* pInputInfo = (SFirstLastRes*)varDataVal(data);
1,386,751,753✔
3101
    if (pCtx->hasPrimaryKey) {
1,386,751,275✔
3102
      pInputInfo->pkData = pInputInfo->buf + pInputInfo->bytes;
4,103,320✔
3103
    } else {
3104
      pInputInfo->pkData = NULL;
1,382,648,672✔
3105
    }
3106

3107
    int32_t code = firstLastTransferInfo(pCtx, pInputInfo, pInfo, isFirstQuery, i);
1,386,748,144✔
3108
    if (code != TSDB_CODE_SUCCESS) {
1,386,753,928✔
3109
      return code;
×
3110
    }
3111
    if (!numOfElems) {
1,386,753,928✔
3112
      numOfElems = pInputInfo->hasResult ? 1 : 0;
640,002,340✔
3113
    }
3114
  }
3115

3116
  if (numOfElems == 0) {
643,960,746✔
3117
    int32_t code = firstlastSaveTupleData(pCtx->pSrcBlock, pInput->startRowIndex, pCtx, pInfo, true);
3,961,035✔
3118
    if (code != TSDB_CODE_SUCCESS) {
3,961,035✔
3119
      return code;
×
3120
    }
3121
    pInfo->nullTupleSaved = true;
3,961,035✔
3122
  }
3123

3124
  SET_VAL(GET_RES_INFO(pCtx), numOfElems, 1);
643,961,702✔
3125
  return TSDB_CODE_SUCCESS;
643,961,224✔
3126
}
3127

3128
int32_t firstFunctionMerge(SqlFunctionCtx* pCtx) { return firstLastFunctionMergeImpl(pCtx, true); }
375,240,837✔
3129

3130
int32_t lastFunctionMerge(SqlFunctionCtx* pCtx) { return firstLastFunctionMergeImpl(pCtx, false); }
268,724,211✔
3131

3132
int32_t firstLastFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
2,147,483,647✔
3133
  int32_t          code = TSDB_CODE_SUCCESS;
2,147,483,647✔
3134
  int32_t          slotId = pCtx->pExpr->base.resSchema.slotId;
2,147,483,647✔
3135
  SColumnInfoData* pCol = taosArrayGet(pBlock->pDataBlock, slotId);
2,147,483,647✔
3136
  if (NULL == pCol) {
2,147,483,647✔
3137
    return TSDB_CODE_OUT_OF_RANGE;
×
3138
  }
3139

3140
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
2,147,483,647✔
3141
  pResInfo->isNullRes = (pResInfo->numOfRes == 0) ? 1 : 0;
2,147,483,647✔
3142

3143
  SFirstLastRes* pRes = GET_ROWCELL_INTERBUF(pResInfo);
2,147,483,647✔
3144

3145
  if (pResInfo->isNullRes) {
2,147,483,647✔
3146
    colDataSetNULL(pCol, pBlock->info.rows);
2,147,483,647✔
3147
    return setNullSelectivityValue(pCtx, pBlock, pBlock->info.rows);
2,147,483,647✔
3148
  }
3149
  code = colDataSetVal(pCol, pBlock->info.rows, pRes->buf, pRes->isNull || pResInfo->isNullRes);
2,147,483,647✔
3150
  if (TSDB_CODE_SUCCESS != code) {
2,147,483,647✔
3151
    return code;
×
3152
  }
3153

3154
  // handle selectivity
3155
  code = setSelectivityValue(pCtx, pBlock, &pRes->pos, pBlock->info.rows);
2,147,483,647✔
3156
  if (TSDB_CODE_SUCCESS != code) {
2,147,483,647✔
3157
    qError("%s failed at %d, msg:%s", __func__, __LINE__, tstrerror(code));
×
3158
  }
3159

3160
  return code;
2,147,483,647✔
3161
}
3162

3163
int32_t firstLastPartialFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
1,724,920,465✔
3164
  int32_t code = TSDB_CODE_SUCCESS;
1,724,920,465✔
3165

3166
  SResultRowEntryInfo* pEntryInfo = GET_RES_INFO(pCtx);
1,724,920,465✔
3167
  SFirstLastRes*       pRes = GET_ROWCELL_INTERBUF(pEntryInfo);
1,725,365,678✔
3168

3169
  int32_t resultBytes = getFirstLastInfoSize(pRes->bytes, pRes->pkBytes);
1,725,366,248✔
3170

3171
  // todo check for failure
3172
  char* res = taosMemoryCalloc(resultBytes + VARSTR_HEADER_SIZE, sizeof(char));
1,724,891,050✔
3173
  if (NULL == res) {
1,719,330,304✔
3174
    return terrno;
×
3175
  }
3176
  (void)memcpy(varDataVal(res), pRes, resultBytes);
1,719,330,304✔
3177

3178
  varDataSetLen(res, resultBytes);
1,719,367,634✔
3179

3180
  int32_t          slotId = pCtx->pExpr->base.resSchema.slotId;
1,723,263,882✔
3181
  SColumnInfoData* pCol = taosArrayGet(pBlock->pDataBlock, slotId);
1,725,177,629✔
3182
  if (NULL == pCol) {
1,725,000,077✔
3183
    taosMemoryFree(res);
×
3184
    return TSDB_CODE_OUT_OF_RANGE;
×
3185
  }
3186

3187
  if (pEntryInfo->numOfRes == 0) {
1,725,000,077✔
3188
    colDataSetNULL(pCol, pBlock->info.rows);
246,777,583✔
3189
    code = setNullSelectivityValue(pCtx, pBlock, pBlock->info.rows);
246,748,350✔
3190
  } else {
3191
    code = colDataSetVal(pCol, pBlock->info.rows, res, false);
1,477,956,119✔
3192
    if (TSDB_CODE_SUCCESS != code) {
1,477,814,510✔
3193
      taosMemoryFree(res);
×
3194
      return code;
×
3195
    }
3196
    code = setSelectivityValue(pCtx, pBlock, &pRes->pos, pBlock->info.rows);
1,477,814,510✔
3197
  }
3198
  taosMemoryFree(res);
1,724,610,838✔
3199
  return code;
1,724,584,975✔
3200
}
3201

3202
int32_t lastCombine(SqlFunctionCtx* pDestCtx, SqlFunctionCtx* pSourceCtx) {
×
3203
  SResultRowEntryInfo* pDResInfo = GET_RES_INFO(pDestCtx);
×
3204
  SFirstLastRes*       pDBuf = GET_ROWCELL_INTERBUF(pDResInfo);
×
3205
  int32_t              bytes = pDBuf->bytes;
×
3206

3207
  SResultRowEntryInfo* pSResInfo = GET_RES_INFO(pSourceCtx);
×
3208
  SFirstLastRes*       pSBuf = GET_ROWCELL_INTERBUF(pSResInfo);
×
3209

3210
  pDBuf->hasResult = firstLastTransferInfoImpl(pSBuf, pDBuf, false);
×
3211
  pDResInfo->numOfRes = TMAX(pDResInfo->numOfRes, pSResInfo->numOfRes);
×
3212
  pDResInfo->isNullRes &= pSResInfo->isNullRes;
×
3213
  return TSDB_CODE_SUCCESS;
×
3214
}
3215

3216
static int32_t doSaveLastrow(SqlFunctionCtx* pCtx, char* pData, int32_t rowIndex, int64_t cts, SFirstLastRes* pInfo) {
23,447,444✔
3217
  SInputColumnInfoData* pInput = &pCtx->input;
23,447,444✔
3218
  SColumnInfoData*      pInputCol = pInput->pData[0];
23,450,590✔
3219
  SColumnInfoData*      pkCol = pInput->pPrimaryKey;
23,342,484✔
3220

3221
  if (colDataIsNull_s(pInputCol, rowIndex)) {
46,898,569✔
3222
    pInfo->isNull = true;
2,875,916✔
3223
  } else {
3224
    pInfo->isNull = false;
20,567,480✔
3225

3226
    if (IS_VAR_DATA_TYPE(pInputCol->info.type)) {
20,575,592✔
3227
      pInfo->bytes = calcStrBytesByType(pInputCol->info.type, pData);
3,724,572✔
3228
      // if (pInputCol->info.type == TSDB_DATA_TYPE_JSON) {
3229
      //   pInfo->bytes = getJsonValueLen(pData);
3230
      // } else {
3231
      //   pInfo->bytes = varDataTLen(pData);
3232
      // }
3233
    }
3234

3235
    (void)memcpy(pInfo->buf, pData, pInfo->bytes);
20,574,900✔
3236
  }
3237

3238
  if (pCtx->hasPrimaryKey && !colDataIsNull_s(pkCol, rowIndex)) {
33,201,456✔
3239
    char* pkData = colDataGetData(pkCol, rowIndex);
9,749,465✔
3240
    if (IS_VAR_DATA_TYPE(pInfo->pkType)) {
9,752,743✔
3241
      pInfo->pkBytes = calcStrBytesByType(pInfo->pkType, pkData);
3,210,154✔
3242
    }
3243
    (void)memcpy(pInfo->buf + pInfo->bytes, pkData, pInfo->pkBytes);
9,752,761✔
3244
    pInfo->pkData = pInfo->buf + pInfo->bytes;
9,749,413✔
3245
  }
3246
  pInfo->ts = cts;
23,454,611✔
3247
  int32_t code = firstlastSaveTupleData(pCtx->pSrcBlock, rowIndex, pCtx, pInfo, false);
23,452,556✔
3248
  if (code != TSDB_CODE_SUCCESS) {
23,443,773✔
3249
    return code;
×
3250
  }
3251

3252
  pInfo->hasResult = true;
23,443,773✔
3253

3254
  return TSDB_CODE_SUCCESS;
23,442,451✔
3255
}
3256

3257
int32_t lastRowFunction(SqlFunctionCtx* pCtx) {
2,147,483,647✔
3258
  int32_t numOfElems = 0;
2,147,483,647✔
3259

3260
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
2,147,483,647✔
3261
  SFirstLastRes*       pInfo = GET_ROWCELL_INTERBUF(pResInfo);
2,147,483,647✔
3262

3263
  SInputColumnInfoData* pInput = &pCtx->input;
2,147,483,647✔
3264
  SColumnInfoData*      pInputCol = pInput->pData[0];
2,147,483,647✔
3265

3266
  int32_t type = pInputCol->info.type;
2,147,483,647✔
3267
  int32_t bytes = pInputCol->info.bytes;
2,147,483,647✔
3268
  pInfo->bytes = bytes;
2,147,483,647✔
3269

3270
  if (IS_NULL_TYPE(type)) {
2,147,483,647✔
3271
    return TSDB_CODE_SUCCESS;
18,793✔
3272
  }
3273
  SColumnInfoData* pkCol = pInput->pPrimaryKey;
2,147,483,647✔
3274
  pInfo->pkType = -1;
2,147,483,647✔
3275
  __compar_fn_t pkCompareFn = NULL;
2,147,483,647✔
3276
  if (pCtx->hasPrimaryKey) {
2,147,483,647✔
3277
    pInfo->pkType = pkCol->info.type;
10,069,496✔
3278
    pInfo->pkBytes = pkCol->info.bytes;
10,070,824✔
3279
    pkCompareFn = getKeyComparFunc(pInfo->pkType, TSDB_ORDER_DESC);
10,066,836✔
3280
  }
3281
  TSKEY startKey = getRowPTs(pInput->pPTS, 0);
2,147,483,647✔
3282
  TSKEY endKey = getRowPTs(pInput->pPTS, pInput->totalRows - 1);
2,147,483,647✔
3283

3284
  if (pCtx->order == TSDB_ORDER_ASC && !pCtx->hasPrimaryKey) {
2,147,483,647✔
3285
    for (int32_t i = pInput->numOfRows + pInput->startRowIndex - 1; i >= pInput->startRowIndex; --i) {
21,107,322✔
3286
      bool  isNull = colDataIsNull(pInputCol, pInput->numOfRows, i, NULL);
10,552,043✔
3287
      char* data = isNull ? NULL : colDataGetData(pInputCol, i);
10,552,526✔
3288
      TSKEY cts = getRowPTs(pInput->pPTS, i);
10,555,012✔
3289
      numOfElems++;
10,556,828✔
3290

3291
      if (pResInfo->numOfRes == 0 || pInfo->ts < cts) {
10,556,828✔
3292
        int32_t code = doSaveLastrow(pCtx, data, i, cts, pInfo);
2,963,414✔
3293
        if (code != TSDB_CODE_SUCCESS) return code;
2,962,931✔
3294
      }
3295

3296
      break;
10,555,733✔
3297
    }
3298
  } else if (pCtx->order == TSDB_ORDER_DESC && !pCtx->hasPrimaryKey) {
2,147,483,647✔
3299
    // the optimized version only valid if all tuples in one block are monotonious increasing or descreasing.
3300
    // this assumption is NOT always works if project operator exists in downstream.
3301
    for (int32_t i = pInput->startRowIndex; i < pInput->numOfRows + pInput->startRowIndex; ++i) {
2,147,483,647✔
3302
      bool  isNull = colDataIsNull(pInputCol, pInput->numOfRows, i, NULL);
2,147,483,647✔
3303
      char* data = isNull ? NULL : colDataGetData(pInputCol, i);
2,147,483,647✔
3304
      TSKEY cts = getRowPTs(pInput->pPTS, i);
2,147,483,647✔
3305
      numOfElems++;
2,147,483,647✔
3306

3307
      if (pResInfo->numOfRes == 0 || pInfo->ts < cts) {
2,147,483,647✔
3308
        int32_t code = doSaveLastrow(pCtx, data, i, cts, pInfo);
8,393,749✔
3309
        if (code != TSDB_CODE_SUCCESS) return code;
8,689,418✔
3310
      }
3311
      break;
2,147,483,647✔
3312
    }
3313
  } else {
3314
    int64_t* pts = (int64_t*)pInput->pPTS->pData;
10,554,214✔
3315
    int      from = -1;
10,617,476✔
3316
    int32_t  i = -1;
10,617,727✔
3317
    while (funcInputGetNextRowIndex(pInput, from, false, &i, &from)) {
195,994,734✔
3318
      bool  isNull = colDataIsNull(pInputCol, pInput->numOfRows, i, NULL);
185,366,036✔
3319
      char* data = isNull ? NULL : colDataGetData(pInputCol, i);
185,371,524✔
3320
      TSKEY cts = pts[i];
185,367,808✔
3321

3322
      numOfElems++;
185,370,721✔
3323
      char* pkData = NULL;
185,370,721✔
3324
      if (pCtx->hasPrimaryKey) {
185,370,721✔
3325
        pkData = colDataGetData(pkCol, i);
180,865,286✔
3326
      }
3327
      if (pResInfo->numOfRes == 0 || pInfo->ts < cts ||
185,381,758✔
3328
          (pInfo->ts == pts[i] && pkCompareFn && pkCompareFn(pkData, pInfo->pkData) < 0)) {
174,105,939✔
3329
        int32_t code = doSaveLastrow(pCtx, data, i, cts, pInfo);
11,275,695✔
3330
        if (code != TSDB_CODE_SUCCESS) {
11,281,041✔
3331
          return code;
×
3332
        }
3333
        pResInfo->numOfRes = 1;
11,281,041✔
3334
      }
3335
    }
3336
  }
3337

3338
  SET_VAL(pResInfo, numOfElems, 1);
2,147,483,647✔
3339
  return TSDB_CODE_SUCCESS;
2,147,483,647✔
3340
}
3341

3342
bool getDiffFuncEnv(SFunctionNode* UNUSED_PARAM(pFunc), SFuncExecEnv* pEnv) {
532,782✔
3343
  pEnv->calcMemSize = sizeof(SDiffInfo);
532,782✔
3344
  return true;
532,782✔
3345
}
3346

3347
int32_t diffFunctionSetup(SqlFunctionCtx* pCtx, SResultRowEntryInfo* pResInfo) {
45,931,779✔
3348
  if (pResInfo->initialized) {
45,931,779✔
3349
    return TSDB_CODE_SUCCESS;
40,216,820✔
3350
  }
3351
  if (TSDB_CODE_SUCCESS != functionSetup(pCtx, pResInfo)) {
5,714,959✔
3352
    return TSDB_CODE_FUNC_SETUP_ERROR;
×
3353
  }
3354
  SDiffInfo* pDiffInfo = GET_ROWCELL_INTERBUF(pResInfo);
5,714,959✔
3355
  pDiffInfo->hasPrev = false;
5,714,959✔
3356
  pDiffInfo->isFirstRow = true;
5,714,959✔
3357
  pDiffInfo->prev.i64 = 0;
5,714,959✔
3358
  pDiffInfo->prevTs = -1;
5,714,959✔
3359
  if (pCtx->numOfParams > 1) {
5,714,959✔
3360
    pDiffInfo->ignoreOption = pCtx->param[1].param.i;  // TODO set correct param
5,714,959✔
3361
  } else {
3362
    pDiffInfo->ignoreOption = 0;
×
3363
  }
3364
  return TSDB_CODE_SUCCESS;
5,714,959✔
3365
}
3366

3367
static int32_t doSetPrevVal(SDiffInfo* pDiffInfo, int32_t type, const char* pv, int64_t ts) {
5,617,613✔
3368
  switch (type) {
5,617,613✔
3369
    case TSDB_DATA_TYPE_BOOL:
3,965✔
3370
      pDiffInfo->prev.i64 = *(bool*)pv ? 1 : 0;
3,965✔
3371
      break;
3,965✔
3372
    case TSDB_DATA_TYPE_UTINYINT:
44,688✔
3373
    case TSDB_DATA_TYPE_TINYINT:
3374
      pDiffInfo->prev.i64 = *(int8_t*)pv;
44,688✔
3375
      break;
44,688✔
3376
    case TSDB_DATA_TYPE_UINT:
5,333,345✔
3377
    case TSDB_DATA_TYPE_INT:
3378
      pDiffInfo->prev.i64 = *(int32_t*)pv;
5,333,345✔
3379
      break;
5,333,345✔
3380
    case TSDB_DATA_TYPE_USMALLINT:
33,156✔
3381
    case TSDB_DATA_TYPE_SMALLINT:
3382
      pDiffInfo->prev.i64 = *(int16_t*)pv;
33,156✔
3383
      break;
33,156✔
3384
    case TSDB_DATA_TYPE_TIMESTAMP:
114,260✔
3385
    case TSDB_DATA_TYPE_UBIGINT:
3386
    case TSDB_DATA_TYPE_BIGINT:
3387
      pDiffInfo->prev.i64 = *(int64_t*)pv;
114,260✔
3388
      break;
114,260✔
3389
    case TSDB_DATA_TYPE_FLOAT:
27,391✔
3390
      pDiffInfo->prev.d64 = *(float*)pv;
27,391✔
3391
      break;
27,391✔
3392
    case TSDB_DATA_TYPE_DOUBLE:
60,808✔
3393
      pDiffInfo->prev.d64 = *(double*)pv;
60,808✔
3394
      break;
60,808✔
3395
    default:
×
3396
      return TSDB_CODE_FUNC_FUNTION_PARA_TYPE;
×
3397
  }
3398
  pDiffInfo->prevTs = ts;
5,617,613✔
3399
  pDiffInfo->hasPrev = true;
5,617,613✔
3400
  return TSDB_CODE_SUCCESS;
5,617,613✔
3401
}
3402

3403
static bool diffIsNegtive(SDiffInfo* pDiffInfo, int32_t type, const char* pv) {
3,383,754✔
3404
  switch (type) {
3,383,754✔
3405
    case TSDB_DATA_TYPE_UINT: {
×
3406
      int64_t v = *(uint32_t*)pv;
×
3407
      return v < pDiffInfo->prev.i64;
×
3408
    }
3409
    case TSDB_DATA_TYPE_INT: {
322,830✔
3410
      int64_t v = *(int32_t*)pv;
322,830✔
3411
      return v < pDiffInfo->prev.i64;
322,830✔
3412
    }
3413
    case TSDB_DATA_TYPE_BOOL: {
×
3414
      int64_t v = *(bool*)pv;
×
3415
      return v < pDiffInfo->prev.i64;
×
3416
    }
3417
    case TSDB_DATA_TYPE_UTINYINT: {
×
3418
      int64_t v = *(uint8_t*)pv;
×
3419
      return v < pDiffInfo->prev.i64;
×
3420
    }
3421
    case TSDB_DATA_TYPE_TINYINT: {
881,660✔
3422
      int64_t v = *(int8_t*)pv;
881,660✔
3423
      return v < pDiffInfo->prev.i64;
881,660✔
3424
    }
3425
    case TSDB_DATA_TYPE_USMALLINT: {
×
3426
      int64_t v = *(uint16_t*)pv;
×
3427
      return v < pDiffInfo->prev.i64;
×
3428
    }
3429
    case TSDB_DATA_TYPE_SMALLINT: {
855,362✔
3430
      int64_t v = *(int16_t*)pv;
855,362✔
3431
      return v < pDiffInfo->prev.i64;
855,362✔
3432
    }
3433
    case TSDB_DATA_TYPE_UBIGINT: {
3,528✔
3434
      uint64_t v = *(uint64_t*)pv;
3,528✔
3435
      return v < (uint64_t)pDiffInfo->prev.i64;
3,528✔
3436
    }
3437
    case TSDB_DATA_TYPE_TIMESTAMP:
216,434✔
3438
    case TSDB_DATA_TYPE_BIGINT: {
3439
      int64_t v = *(int64_t*)pv;
216,434✔
3440
      return v < pDiffInfo->prev.i64;
216,434✔
3441
    }
3442
    case TSDB_DATA_TYPE_FLOAT: {
264,078✔
3443
      float v = *(float*)pv;
264,078✔
3444
      return v < pDiffInfo->prev.d64;
264,078✔
3445
    }
3446
    case TSDB_DATA_TYPE_DOUBLE: {
839,862✔
3447
      double v = *(double*)pv;
839,862✔
3448
      return v < pDiffInfo->prev.d64;
839,862✔
3449
    }
3450
    default:
×
3451
      return false;
×
3452
  }
3453

3454
  return false;
3455
}
3456

3457
static void tryToSetInt64(SDiffInfo* pDiffInfo, int32_t type, SColumnInfoData* pOutput, int64_t v, int32_t pos) {
2,147,483,647✔
3458
  bool isNegative = v < pDiffInfo->prev.i64;
2,147,483,647✔
3459
  if (type == TSDB_DATA_TYPE_UBIGINT) {
2,147,483,647✔
3460
    isNegative = (uint64_t)v < (uint64_t)pDiffInfo->prev.i64;
461,271✔
3461
  }
3462
  int64_t delta = v - pDiffInfo->prev.i64;
2,147,483,647✔
3463
  if (isNegative && ignoreNegative(pDiffInfo->ignoreOption)) {
2,147,483,647✔
3464
    colDataSetNull_f_s(pOutput, pos);
1,158,212✔
3465
    pOutput->hasNull = true;
1,158,212✔
3466
  } else {
3467
    colDataSetInt64(pOutput, pos, &delta);
2,147,483,647✔
3468
  }
3469
  pDiffInfo->prev.i64 = v;
2,147,483,647✔
3470
}
2,147,483,647✔
3471

3472
static void tryToSetDouble(SDiffInfo* pDiffInfo, SColumnInfoData* pOutput, double v, int32_t pos) {
29,342,029✔
3473
  double delta = v - pDiffInfo->prev.d64;
29,342,029✔
3474
  if (delta < 0 && ignoreNegative(pDiffInfo->ignoreOption)) {
29,342,029✔
3475
    colDataSetNull_f_s(pOutput, pos);
551,151✔
3476
  } else {
3477
    colDataSetDouble(pOutput, pos, &delta);
28,790,878✔
3478
  }
3479
  pDiffInfo->prev.d64 = v;
29,342,029✔
3480
}
29,342,029✔
3481

3482
static int32_t doHandleDiff(SDiffInfo* pDiffInfo, int32_t type, const char* pv, SColumnInfoData* pOutput, int32_t pos,
2,147,483,647✔
3483
                            int64_t ts) {
3484
  if (!pDiffInfo->hasPrev) {
2,147,483,647✔
3485
    colDataSetNull_f_s(pOutput, pos);
65,343✔
3486
    return doSetPrevVal(pDiffInfo, type, pv, ts);
65,343✔
3487
  }
3488
  pDiffInfo->prevTs = ts;
2,147,483,647✔
3489
  switch (type) {
2,147,483,647✔
3490
    case TSDB_DATA_TYPE_UINT: {
455,097✔
3491
      int64_t v = *(uint32_t*)pv;
455,097✔
3492
      tryToSetInt64(pDiffInfo, type, pOutput, v, pos);
455,097✔
3493
      break;
455,097✔
3494
    }
3495
    case TSDB_DATA_TYPE_INT: {
2,147,483,647✔
3496
      int64_t v = *(int32_t*)pv;
2,147,483,647✔
3497
      tryToSetInt64(pDiffInfo, type, pOutput, v, pos);
2,147,483,647✔
3498
      break;
2,147,483,647✔
3499
    }
3500
    case TSDB_DATA_TYPE_BOOL: {
4,491,950✔
3501
      int64_t v = *(bool*)pv;
4,491,950✔
3502
      tryToSetInt64(pDiffInfo, type, pOutput, v, pos);
4,491,950✔
3503
      break;
4,491,950✔
3504
    }
3505
    case TSDB_DATA_TYPE_UTINYINT: {
59,535✔
3506
      int64_t v = *(uint8_t*)pv;
59,535✔
3507
      tryToSetInt64(pDiffInfo, type, pOutput, v, pos);
59,535✔
3508
      break;
59,535✔
3509
    }
3510
    case TSDB_DATA_TYPE_TINYINT: {
11,321,444✔
3511
      int64_t v = *(int8_t*)pv;
11,321,444✔
3512
      tryToSetInt64(pDiffInfo, type, pOutput, v, pos);
11,321,444✔
3513
      break;
11,321,444✔
3514
    }
3515
    case TSDB_DATA_TYPE_USMALLINT: {
59,535✔
3516
      int64_t v = *(uint16_t*)pv;
59,535✔
3517
      tryToSetInt64(pDiffInfo, type, pOutput, v, pos);
59,535✔
3518
      break;
59,535✔
3519
    }
3520
    case TSDB_DATA_TYPE_SMALLINT: {
10,566,484✔
3521
      int64_t v = *(int16_t*)pv;
10,566,484✔
3522
      tryToSetInt64(pDiffInfo, type, pOutput, v, pos);
10,566,484✔
3523
      break;
10,566,484✔
3524
    }
3525
    case TSDB_DATA_TYPE_TIMESTAMP:
2,147,483,647✔
3526
    case TSDB_DATA_TYPE_UBIGINT:
3527
    case TSDB_DATA_TYPE_BIGINT: {
3528
      int64_t v = *(int64_t*)pv;
2,147,483,647✔
3529
      tryToSetInt64(pDiffInfo, type, pOutput, v, pos);
2,147,483,647✔
3530
      break;
2,147,483,647✔
3531
    }
3532
    case TSDB_DATA_TYPE_FLOAT: {
14,420,007✔
3533
      double v = *(float*)pv;
14,420,007✔
3534
      tryToSetDouble(pDiffInfo, pOutput, v, pos);
14,420,007✔
3535
      break;
14,420,007✔
3536
    }
3537
    case TSDB_DATA_TYPE_DOUBLE: {
14,922,022✔
3538
      double v = *(double*)pv;
14,922,022✔
3539
      tryToSetDouble(pDiffInfo, pOutput, v, pos);
14,922,022✔
3540
      break;
14,922,022✔
3541
    }
3542
    default:
×
3543
      return TSDB_CODE_FUNC_FUNTION_PARA_TYPE;
×
3544
  }
3545
  pDiffInfo->hasPrev = true;
2,147,483,647✔
3546
  return TSDB_CODE_SUCCESS;
2,147,483,647✔
3547
}
3548

3549
// TODO: the primary key compare can be skipped for ordered pk if knonwn before
3550
// TODO: for desc ordered, pk shall select the smallest one for one ts. if across block boundaries.
3551
bool funcInputGetNextRowIndex(SInputColumnInfoData* pInput, int32_t from, bool firstOccur, int32_t* pRowIndex,
2,147,483,647✔
3552
                              int32_t* nextFrom) {
3553
  if (pInput->pPrimaryKey == NULL) {
2,147,483,647✔
3554
    if (pInput->numOfRows == 0) {
2,147,483,647✔
UNCOV
3555
      return false;
×
3556
    }
3557
    if (from == -1) {
2,147,483,647✔
3558
      from = pInput->startRowIndex;
2,147,483,647✔
3559
    } else if (from >= pInput->numOfRows + pInput->startRowIndex) {
2,147,483,647✔
3560
      return false;
2,147,483,647✔
3561
    }
3562
    *pRowIndex = from;
2,147,483,647✔
3563
    *nextFrom = from + 1;
2,147,483,647✔
3564
    return true;
2,147,483,647✔
3565
  } else {
3566
    if (from == -1) {
576,165,927✔
3567
      from = pInput->startRowIndex;
31,478,710✔
3568
    } else if (from >= pInput->numOfRows + pInput->startRowIndex) {
544,687,217✔
3569
      return false;
31,494,504✔
3570
    }
3571
    TSKEY*           tsList = (int64_t*)pInput->pPTS->pData;
544,701,335✔
3572
    SColumnInfoData* pkCol = pInput->pPrimaryKey;
544,746,593✔
3573
    int8_t           pkType = pkCol->info.type;
544,744,575✔
3574
    int32_t          order = (firstOccur) ? TSDB_ORDER_ASC : TSDB_ORDER_DESC;
544,798,553✔
3575
    __compar_fn_t    compareFunc = getKeyComparFunc(pkType, order);
544,798,553✔
3576
    int32_t          select = from;
544,719,219✔
3577
    char*            val = colDataGetData(pkCol, select);
544,719,219✔
3578
    while (from < pInput->numOfRows + pInput->startRowIndex - 1 && tsList[from + 1] == tsList[from]) {
1,363,502,948✔
3579
      char* val1 = colDataGetData(pkCol, from + 1);
818,733,739✔
3580
      if (compareFunc(val1, val) < 0) {
818,818,949✔
3581
        select = from + 1;
263,477,796✔
3582
        val = val1;
263,477,796✔
3583
      }
3584
      from = from + 1;
818,741,711✔
3585
    }
3586
    *pRowIndex = select;
544,054,701✔
3587
    *nextFrom = from + 1;
544,651,349✔
3588
    return true;
544,719,237✔
3589
  }
3590
}
3591

3592
bool getForecastConfEnv(SFunctionNode* UNUSED_PARAM(pFunc), SFuncExecEnv* pEnv) {
×
3593
  pEnv->calcMemSize = sizeof(double);
×
3594
  return true;
×
3595
}
3596

3597
int32_t diffResultIsNull(SqlFunctionCtx* pCtx, SFuncInputRow* pRow) {
2,147,483,647✔
3598
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
2,147,483,647✔
3599
  SDiffInfo*           pDiffInfo = GET_ROWCELL_INTERBUF(pResInfo);
2,147,483,647✔
3600

3601
  if (pRow->isDataNull || !pDiffInfo->hasPrev) {
2,147,483,647✔
3602
    return true;
12,355,313✔
3603
  } else if (ignoreNegative(pDiffInfo->ignoreOption)) {
2,147,483,647✔
3604
    return diffIsNegtive(pDiffInfo, pCtx->input.pData[0]->info.type, pRow->pData);
3,383,754✔
3605
  }
3606
  return false;
2,147,483,647✔
3607
}
3608

3609
bool isFirstRow(SqlFunctionCtx* pCtx, SFuncInputRow* pRow) {
2,147,483,647✔
3610
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
2,147,483,647✔
3611
  SDiffInfo*           pDiffInfo = GET_ROWCELL_INTERBUF(pResInfo);
2,147,483,647✔
3612
  return pDiffInfo->isFirstRow;
2,147,483,647✔
3613
}
3614

3615
int32_t trySetPreVal(SqlFunctionCtx* pCtx, SFuncInputRow* pRow) {
5,723,554✔
3616
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
5,723,554✔
3617
  SDiffInfo*           pDiffInfo = GET_ROWCELL_INTERBUF(pResInfo);
5,723,554✔
3618
  pDiffInfo->isFirstRow = false;
5,723,554✔
3619
  if (pRow->isDataNull) {
5,723,554✔
3620
    return TSDB_CODE_SUCCESS;
171,284✔
3621
  }
3622

3623
  SInputColumnInfoData* pInput = &pCtx->input;
5,552,270✔
3624
  SColumnInfoData*      pInputCol = pInput->pData[0];
5,552,270✔
3625
  int8_t                inputType = pInputCol->info.type;
5,552,270✔
3626

3627
  char* pv = pRow->pData;
5,552,270✔
3628
  return doSetPrevVal(pDiffInfo, inputType, pv, pRow->ts);
5,552,270✔
3629
}
3630

3631
int32_t setDoDiffResult(SqlFunctionCtx* pCtx, SFuncInputRow* pRow, int32_t pos) {
2,147,483,647✔
3632
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
2,147,483,647✔
3633
  SDiffInfo*           pDiffInfo = GET_ROWCELL_INTERBUF(pResInfo);
2,147,483,647✔
3634

3635
  SInputColumnInfoData* pInput = &pCtx->input;
2,147,483,647✔
3636
  SColumnInfoData*      pInputCol = pInput->pData[0];
2,147,483,647✔
3637
  int8_t                inputType = pInputCol->info.type;
2,147,483,647✔
3638
  SColumnInfoData*      pOutput = (SColumnInfoData*)pCtx->pOutput;
2,147,483,647✔
3639
  int32_t               code = TSDB_CODE_SUCCESS;
2,147,483,647✔
3640
  if (pRow->isDataNull) {
2,147,483,647✔
3641
    colDataSetNull_f_s(pOutput, pos);
6,573,913✔
3642
    pOutput->hasNull = true;
6,573,913✔
3643

3644
    // handle selectivity
3645
    if (pCtx->subsidiaries.num > 0) {
6,573,913✔
3646
      code = appendSelectivityCols(pCtx, pRow->block, pRow->rowIndex, pos);
21,160✔
3647
      if (code != TSDB_CODE_SUCCESS) {
21,160✔
3648
        return code;
×
3649
      }
3650
    }
3651
    return TSDB_CODE_SUCCESS;
6,573,913✔
3652
  }
3653

3654
  char* pv = pRow->pData;
2,147,483,647✔
3655

3656
  if (pRow->ts == pDiffInfo->prevTs) {
2,147,483,647✔
3657
    return TSDB_CODE_FUNC_DUP_TIMESTAMP;
7,961✔
3658
  }
3659
  code = doHandleDiff(pDiffInfo, inputType, pv, pOutput, pos, pRow->ts);
2,147,483,647✔
3660
  if (code != TSDB_CODE_SUCCESS) {
2,147,483,647✔
3661
    return code;
×
3662
  }
3663
  // handle selectivity
3664
  if (pCtx->subsidiaries.num > 0) {
2,147,483,647✔
3665
    code = appendSelectivityCols(pCtx, pRow->block, pRow->rowIndex, pos);
2,147,483,647✔
3666
    if (code != TSDB_CODE_SUCCESS) {
2,147,483,647✔
3667
      return code;
×
3668
    }
3669
  }
3670

3671
  return TSDB_CODE_SUCCESS;
2,147,483,647✔
3672
}
3673

3674
int32_t diffFunction(SqlFunctionCtx* pCtx) { return TSDB_CODE_SUCCESS; }
45,398,997✔
3675

3676
int32_t diffFunctionByRow(SArray* pCtxArray) {
45,375,183✔
3677
  int32_t code = TSDB_CODE_SUCCESS;
45,375,183✔
3678
  int     diffColNum = pCtxArray->size;
45,375,183✔
3679
  if (diffColNum == 0) {
45,375,183✔
3680
    return TSDB_CODE_SUCCESS;
×
3681
  }
3682
  int32_t numOfElems = 0;
45,375,183✔
3683

3684
  SArray* pRows = taosArrayInit_s(sizeof(SFuncInputRow), diffColNum);
45,375,183✔
3685
  if (NULL == pRows) {
45,375,183✔
3686
    return terrno;
×
3687
  }
3688

3689
  bool keepNull = false;
45,375,183✔
3690
  for (int i = 0; i < diffColNum; ++i) {
90,774,180✔
3691
    SqlFunctionCtx* pCtx = *(SqlFunctionCtx**)taosArrayGet(pCtxArray, i);
45,398,997✔
3692
    if (NULL == pCtx) {
45,398,997✔
3693
      code = terrno;
×
3694
      goto _exit;
×
3695
    }
3696
    funcInputUpdate(pCtx);
45,398,997✔
3697
    SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
45,398,997✔
3698
    SDiffInfo*           pDiffInfo = GET_ROWCELL_INTERBUF(pResInfo);
45,398,997✔
3699
    if (!ignoreNull(pDiffInfo->ignoreOption)) {
45,398,997✔
3700
      keepNull = true;
45,380,916✔
3701
    }
3702
  }
3703

3704
  SqlFunctionCtx* pCtx0 = *(SqlFunctionCtx**)taosArrayGet(pCtxArray, 0);
45,375,183✔
3705
  SFuncInputRow*  pRow0 = (SFuncInputRow*)taosArrayGet(pRows, 0);
45,375,183✔
3706
  if (NULL == pCtx0 || NULL == pRow0) {
45,375,183✔
3707
    code = terrno;
×
3708
    goto _exit;
×
3709
  }
3710
  int32_t startOffset = pCtx0->offset;
45,375,183✔
3711
  bool    result = false;
45,375,183✔
3712
  while (1) {
2,147,483,647✔
3713
    code = funcInputGetNextRow(pCtx0, pRow0, &result);
2,147,483,647✔
3714
    if (TSDB_CODE_SUCCESS != code) {
2,147,483,647✔
3715
      goto _exit;
×
3716
    }
3717
    if (!result) {
2,147,483,647✔
3718
      break;
45,367,222✔
3719
    }
3720
    bool hasNotNullValue = !diffResultIsNull(pCtx0, pRow0);
2,147,483,647✔
3721
    for (int i = 1; i < diffColNum; ++i) {
2,147,483,647✔
3722
      SqlFunctionCtx* pCtx = *(SqlFunctionCtx**)taosArrayGet(pCtxArray, i);
5,070,618✔
3723
      SFuncInputRow*  pRow = (SFuncInputRow*)taosArrayGet(pRows, i);
5,070,618✔
3724
      if (NULL == pCtx || NULL == pRow) {
5,070,618✔
3725
        code = terrno;
×
3726
        goto _exit;
×
3727
      }
3728
      code = funcInputGetNextRow(pCtx, pRow, &result);
5,070,618✔
3729
      if (TSDB_CODE_SUCCESS != code) {
5,070,618✔
3730
        goto _exit;
×
3731
      }
3732
      if (!result) {
5,070,618✔
3733
        // rows are not equal
3734
        code = TSDB_CODE_QRY_EXECUTOR_INTERNAL_ERROR;
×
3735
        goto _exit;
×
3736
      }
3737
      if (!diffResultIsNull(pCtx, pRow)) {
5,070,618✔
3738
        hasNotNullValue = true;
5,005,350✔
3739
      }
3740
    }
3741
    int32_t pos = startOffset + numOfElems;
2,147,483,647✔
3742

3743
    bool newRow = false;
2,147,483,647✔
3744
    for (int i = 0; i < diffColNum; ++i) {
2,147,483,647✔
3745
      SqlFunctionCtx* pCtx = *(SqlFunctionCtx**)taosArrayGet(pCtxArray, i);
2,147,483,647✔
3746
      SFuncInputRow*  pRow = (SFuncInputRow*)taosArrayGet(pRows, i);
2,147,483,647✔
3747
      if (NULL == pCtx || NULL == pRow) {
2,147,483,647✔
3748
        code = terrno;
×
3749
        goto _exit;
×
3750
      }
3751
      if ((keepNull || hasNotNullValue) && !isFirstRow(pCtx, pRow)) {
2,147,483,647✔
3752
        code = setDoDiffResult(pCtx, pRow, pos);
2,147,483,647✔
3753
        if (code != TSDB_CODE_SUCCESS) {
2,147,483,647✔
3754
          goto _exit;
7,961✔
3755
        }
3756
        newRow = true;
2,147,483,647✔
3757
      } else {
3758
        code = trySetPreVal(pCtx, pRow);
5,723,554✔
3759
        if (code != TSDB_CODE_SUCCESS) {
5,723,554✔
3760
          goto _exit;
×
3761
        }
3762
      }
3763
    }
3764
    if (newRow) ++numOfElems;
2,147,483,647✔
3765
  }
3766

3767
  for (int i = 0; i < diffColNum; ++i) {
90,757,817✔
3768
    SqlFunctionCtx* pCtx = *(SqlFunctionCtx**)taosArrayGet(pCtxArray, i);
45,390,595✔
3769
    if (NULL == pCtx) {
45,390,595✔
3770
      code = terrno;
×
3771
      goto _exit;
×
3772
    }
3773
    SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
45,390,595✔
3774
    pResInfo->numOfRes = numOfElems;
45,390,595✔
3775
  }
3776

3777
_exit:
45,375,183✔
3778
  if (pRows) {
45,375,183✔
3779
    taosArrayDestroy(pRows);
45,375,183✔
3780
    pRows = NULL;
45,375,183✔
3781
  }
3782
  return code;
45,375,183✔
3783
}
3784

3785
typedef struct {
3786
  SArray* pLagTail;
3787
  SArray* pLeadPending;
3788
} SLagLeadState;
3789

3790
bool getLagFuncEnv(SFunctionNode* UNUSED_PARAM(pFunc), SFuncExecEnv* pEnv) {
18,875✔
3791
  pEnv->calcMemSize = sizeof(SLagLeadState);
18,875✔
3792
  return true;
18,875✔
3793
}
3794

3795
int32_t lagFunctionSetup(SqlFunctionCtx* pCtx, SResultRowEntryInfo* pResInfo) {
41,366✔
3796
  if (pResInfo->initialized) {
41,366✔
3797
    return TSDB_CODE_SUCCESS;
21,587✔
3798
  }
3799
  if (TSDB_CODE_SUCCESS != functionSetup(pCtx, pResInfo)) {
19,779✔
NEW
3800
    return TSDB_CODE_FUNC_SETUP_ERROR;
×
3801
  }
3802

3803
  SLagLeadState* pState = GET_ROWCELL_INTERBUF(pResInfo);
19,779✔
3804
  if (pState != NULL) {
19,779✔
3805
    pState->pLagTail = NULL;
19,779✔
3806
    pState->pLeadPending = NULL;
19,779✔
3807
  }
3808

3809
  return TSDB_CODE_SUCCESS;
19,779✔
3810
}
3811

3812
int32_t lagFunction(SqlFunctionCtx* UNUSED_PARAM(pCtx)) { return TSDB_CODE_SUCCESS; }
22,491✔
3813

3814
typedef struct {
3815
  bool        isDataNull;
3816
  char*       pData;
3817
  int32_t     dataLen;
3818
  SSDataBlock* block;
3819
  int32_t     rowIndex;
3820
} SLagLeadRowValue;
3821

3822
typedef struct {
3823
  int32_t outputPos;
3824
  int64_t needIdx;
3825
} SLeadPendingItem;
3826

3827
static void cleanupLagLeadRowValueArray(SArray* pValues) {
74,691✔
3828
  if (pValues == NULL) {
74,691✔
NEW
3829
    return;
×
3830
  }
3831

3832
  int32_t size = taosArrayGetSize(pValues);
74,691✔
3833
  for (int32_t i = 0; i < size; ++i) {
47,512,753✔
3834
    SLagLeadRowValue* pValue = (SLagLeadRowValue*)taosArrayGet(pValues, i);
47,438,062✔
3835
    if (pValue != NULL && pValue->pData != NULL) {
47,438,062✔
3836
      taosMemoryFree(pValue->pData);
47,433,542✔
3837
      pValue->pData = NULL;
47,433,542✔
3838
    }
3839
  }
3840

3841
  taosArrayDestroy(pValues);
74,691✔
3842
}
3843

3844
static void cleanupLagLeadValueArrays(SArray* pValueArrays) {
49,291✔
3845
  if (pValueArrays == NULL) {
49,291✔
NEW
3846
    return;
×
3847
  }
3848

3849
  int32_t size = taosArrayGetSize(pValueArrays);
49,291✔
3850
  for (int32_t i = 0; i < size; ++i) {
101,491✔
3851
    SArray** ppValues = (SArray**)taosArrayGet(pValueArrays, i);
52,200✔
3852
    if (ppValues != NULL && *ppValues != NULL) {
52,200✔
3853
      cleanupLagLeadRowValueArray(*ppValues);
52,200✔
3854
    }
3855
  }
3856

3857
  taosArrayDestroy(pValueArrays);
49,291✔
3858
}
3859

3860
static int32_t copyLagLeadRowValue(SqlFunctionCtx* pCtx, SFuncInputRow* pRow, SLagLeadRowValue* pValue) {
36,304,106✔
3861
  pValue->isDataNull = pRow->isDataNull;
36,304,106✔
3862
  pValue->pData = NULL;
36,304,106✔
3863
  pValue->dataLen = 0;
36,304,106✔
3864
  pValue->block = pRow->block;
36,304,106✔
3865
  pValue->rowIndex = pRow->rowIndex;
36,304,106✔
3866

3867
  if (pRow->isDataNull) {
36,304,106✔
3868
    return TSDB_CODE_SUCCESS;
3,616✔
3869
  }
3870

3871
  SColumnInfoData* pInputCol = pCtx->input.pData[0];
36,300,490✔
3872
  int32_t          dataLen = pInputCol->info.bytes;
36,300,490✔
3873
  if (IS_VAR_DATA_TYPE(pInputCol->info.type)) {
36,300,490✔
3874
    dataLen = IS_STR_DATA_BLOB(pInputCol->info.type) ? blobDataTLen(pRow->pData) : varDataTLen(pRow->pData);
4,530,848✔
3875
  }
3876
  pValue->dataLen = dataLen;
36,300,490✔
3877
  pValue->pData = taosMemoryMalloc(dataLen);
36,300,490✔
3878
  if (pValue->pData == NULL) {
36,300,490✔
NEW
3879
    return terrno;
×
3880
  }
3881

3882
  (void)memcpy(pValue->pData, pRow->pData, dataLen);
36,300,490✔
3883
  return TSDB_CODE_SUCCESS;
36,300,490✔
3884
}
3885

3886
static int32_t setLagLeadDefaultValue(SqlFunctionCtx* pCtx, int32_t pos) {
12,798,046✔
3887
  if (pCtx->numOfParams < 3) {
12,798,046✔
NEW
3888
    colDataSetNULL((SColumnInfoData*)pCtx->pOutput, pos);
×
NEW
3889
    return TSDB_CODE_SUCCESS;
×
3890
  }
3891

3892
  SVariant* pDefault = &pCtx->param[2].param;
12,798,046✔
3893

3894
  if (IS_NULL_TYPE(pDefault->nType)) {
12,798,046✔
3895
    colDataSetNULL((SColumnInfoData*)pCtx->pOutput, pos);
23,024✔
3896
    return TSDB_CODE_SUCCESS;
23,024✔
3897
  }
3898

3899
  SColumnInfoData* pOutput = (SColumnInfoData*)pCtx->pOutput;
12,775,022✔
3900
  uint8_t          type = pOutput->info.type;
12,775,022✔
3901
  STypeMod         inputTypeMod = pCtx->param[2].pCol == NULL ? 0 : typeGetTypeModFromCol(pCtx->param[2].pCol);
12,775,022✔
3902
  int32_t          retCode = TSDB_CODE_SUCCESS;
12,775,022✔
3903

3904
  switch (type) {
12,775,022✔
NEW
3905
    case TSDB_DATA_TYPE_BOOL: {
×
NEW
3906
      bool v = false;
×
NEW
3907
      GET_TYPED_DATA(v, bool, pDefault->nType, &pDefault->i, inputTypeMod);
×
NEW
3908
      retCode = colDataSetVal(pOutput, pos, (const char*)&v, false);
×
NEW
3909
      break;
×
3910
    }
NEW
3911
    case TSDB_DATA_TYPE_TINYINT: {
×
NEW
3912
      int8_t v = 0;
×
NEW
3913
      GET_TYPED_DATA(v, int8_t, pDefault->nType, &pDefault->i, inputTypeMod);
×
NEW
3914
      retCode = colDataSetVal(pOutput, pos, (const char*)&v, false);
×
NEW
3915
      break;
×
3916
    }
NEW
3917
    case TSDB_DATA_TYPE_UTINYINT: {
×
NEW
3918
      uint8_t v = 0;
×
NEW
3919
      GET_TYPED_DATA(v, uint8_t, pDefault->nType, &pDefault->i, inputTypeMod);
×
NEW
3920
      retCode = colDataSetVal(pOutput, pos, (const char*)&v, false);
×
NEW
3921
      break;
×
3922
    }
NEW
3923
    case TSDB_DATA_TYPE_SMALLINT: {
×
NEW
3924
      int16_t v = 0;
×
NEW
3925
      GET_TYPED_DATA(v, int16_t, pDefault->nType, &pDefault->i, inputTypeMod);
×
NEW
3926
      retCode = colDataSetVal(pOutput, pos, (const char*)&v, false);
×
NEW
3927
      break;
×
3928
    }
NEW
3929
    case TSDB_DATA_TYPE_USMALLINT: {
×
NEW
3930
      uint16_t v = 0;
×
NEW
3931
      GET_TYPED_DATA(v, uint16_t, pDefault->nType, &pDefault->i, inputTypeMod);
×
NEW
3932
      retCode = colDataSetVal(pOutput, pos, (const char*)&v, false);
×
NEW
3933
      break;
×
3934
    }
3935
    case TSDB_DATA_TYPE_INT: {
12,764,830✔
3936
      int32_t v = 0;
12,764,830✔
3937
      GET_TYPED_DATA(v, int32_t, pDefault->nType, &pDefault->i, inputTypeMod);
12,764,830✔
3938
      retCode = colDataSetVal(pOutput, pos, (const char*)&v, false);
12,764,830✔
3939
      break;
12,764,830✔
3940
    }
NEW
3941
    case TSDB_DATA_TYPE_UINT: {
×
NEW
3942
      uint32_t v = 0;
×
NEW
3943
      GET_TYPED_DATA(v, uint32_t, pDefault->nType, &pDefault->i, inputTypeMod);
×
NEW
3944
      retCode = colDataSetVal(pOutput, pos, (const char*)&v, false);
×
NEW
3945
      break;
×
3946
    }
3947
    case TSDB_DATA_TYPE_BIGINT:
2,508✔
3948
    case TSDB_DATA_TYPE_TIMESTAMP: {
3949
      if (type == TSDB_DATA_TYPE_TIMESTAMP && IS_STR_DATA_TYPE(pDefault->nType)) {
2,508✔
3950
        int64_t tsVal = 0;
1,655✔
3951
        int32_t cvtCode = convertStringToTimestamp(pDefault->nType, pDefault->pz, pOutput->info.precision, &tsVal,
1,655✔
3952
                     NULL, NULL);
3953
        if (cvtCode != TSDB_CODE_SUCCESS) {
1,655✔
NEW
3954
          retCode = cvtCode;
×
NEW
3955
          break;
×
3956
        }
3957
        retCode = colDataSetVal(pOutput, pos, (const char*)&tsVal, false);
1,655✔
3958
        break;
1,655✔
3959
      }
3960

3961
      int64_t v = 0;
853✔
3962
      GET_TYPED_DATA(v, int64_t, pDefault->nType, &pDefault->i, inputTypeMod);
853✔
3963
      retCode = colDataSetVal(pOutput, pos, (const char*)&v, false);
853✔
3964
      break;
853✔
3965
    }
NEW
3966
    case TSDB_DATA_TYPE_UBIGINT: {
×
NEW
3967
      uint64_t v = 0;
×
NEW
3968
      GET_TYPED_DATA(v, uint64_t, pDefault->nType, &pDefault->i, inputTypeMod);
×
NEW
3969
      retCode = colDataSetVal(pOutput, pos, (const char*)&v, false);
×
NEW
3970
      break;
×
3971
    }
NEW
3972
    case TSDB_DATA_TYPE_FLOAT: {
×
NEW
3973
      float v = 0;
×
NEW
3974
      GET_TYPED_DATA(v, float, pDefault->nType, &pDefault->i, inputTypeMod);
×
NEW
3975
      retCode = colDataSetVal(pOutput, pos, (const char*)&v, false);
×
NEW
3976
      break;
×
3977
    }
NEW
3978
    case TSDB_DATA_TYPE_DOUBLE: {
×
NEW
3979
      double v = 0;
×
NEW
3980
      GET_TYPED_DATA(v, double, pDefault->nType, &pDefault->i, inputTypeMod);
×
NEW
3981
      retCode = colDataSetVal(pOutput, pos, (const char*)&v, false);
×
NEW
3982
      break;
×
3983
    }
3984
    case TSDB_DATA_TYPE_DECIMAL64: {
1,808✔
3985
      Decimal64 v = {0};
1,808✔
3986
      switch (pDefault->nType) {
1,808✔
NEW
3987
        case TSDB_DATA_TYPE_BOOL:
×
NEW
3988
          retCode = TEST_decimal64From_uint64_t(&v, pOutput->info.precision, pOutput->info.scale, (uint64_t)pDefault->i);
×
NEW
3989
          break;
×
NEW
3990
        case TSDB_DATA_TYPE_TINYINT:
×
3991
        case TSDB_DATA_TYPE_SMALLINT:
3992
        case TSDB_DATA_TYPE_INT:
3993
        case TSDB_DATA_TYPE_BIGINT:
3994
        case TSDB_DATA_TYPE_TIMESTAMP:
NEW
3995
          retCode = TEST_decimal64From_int64_t(&v, pOutput->info.precision, pOutput->info.scale, pDefault->i);
×
NEW
3996
          break;
×
NEW
3997
        case TSDB_DATA_TYPE_UTINYINT:
×
3998
        case TSDB_DATA_TYPE_USMALLINT:
3999
        case TSDB_DATA_TYPE_UINT:
4000
        case TSDB_DATA_TYPE_UBIGINT:
NEW
4001
          retCode = TEST_decimal64From_uint64_t(&v, pOutput->info.precision, pOutput->info.scale, pDefault->u);
×
NEW
4002
          break;
×
NEW
4003
        case TSDB_DATA_TYPE_FLOAT:
×
NEW
4004
          retCode = TEST_decimal64From_double(&v, pOutput->info.precision, pOutput->info.scale, pDefault->f);
×
NEW
4005
          break;
×
4006
        case TSDB_DATA_TYPE_DOUBLE:
1,808✔
4007
          retCode = TEST_decimal64From_double(&v, pOutput->info.precision, pOutput->info.scale, pDefault->d);
1,808✔
4008
          break;
1,808✔
NEW
4009
        case TSDB_DATA_TYPE_DECIMAL64: {
×
NEW
4010
          uint8_t inputPrecision = 0, inputScale = 0;
×
NEW
4011
          extractTypeFromTypeMod(pDefault->nType, inputTypeMod, &inputPrecision, &inputScale, NULL);
×
NEW
4012
          retCode = TEST_decimal64FromDecimal64((Decimal64*)&pDefault->i, inputPrecision, inputScale, &v,
×
NEW
4013
                                                pOutput->info.precision, pOutput->info.scale);
×
NEW
4014
          break;
×
4015
        }
NEW
4016
        case TSDB_DATA_TYPE_DECIMAL: {
×
NEW
4017
          uint8_t inputPrecision = 0, inputScale = 0;
×
NEW
4018
          extractTypeFromTypeMod(pDefault->nType, inputTypeMod, &inputPrecision, &inputScale, NULL);
×
NEW
4019
          retCode = TEST_decimal64FromDecimal128((Decimal128*)pDefault->pz, inputPrecision, inputScale, &v,
×
NEW
4020
                                                 pOutput->info.precision, pOutput->info.scale);
×
NEW
4021
          break;
×
4022
        }
NEW
4023
        default:
×
NEW
4024
          retCode = TSDB_CODE_OPS_NOT_SUPPORT;
×
NEW
4025
          break;
×
4026
      }
4027

4028
      if (retCode == TSDB_CODE_SUCCESS) {
1,808✔
4029
        retCode = colDataSetVal(pOutput, pos, (const char*)&v, false);
1,808✔
4030
      }
4031
      break;
1,808✔
4032
    }
NEW
4033
    case TSDB_DATA_TYPE_DECIMAL: {
×
NEW
4034
      Decimal128 v = {0};
×
NEW
4035
      switch (pDefault->nType) {
×
NEW
4036
        case TSDB_DATA_TYPE_BOOL:
×
4037
          retCode =
NEW
4038
              TEST_decimal128From_uint64_t(&v, pOutput->info.precision, pOutput->info.scale, (uint64_t)pDefault->i);
×
NEW
4039
          break;
×
NEW
4040
        case TSDB_DATA_TYPE_TINYINT:
×
4041
        case TSDB_DATA_TYPE_SMALLINT:
4042
        case TSDB_DATA_TYPE_INT:
4043
        case TSDB_DATA_TYPE_BIGINT:
4044
        case TSDB_DATA_TYPE_TIMESTAMP:
NEW
4045
          retCode = TEST_decimal128From_int64_t(&v, pOutput->info.precision, pOutput->info.scale, pDefault->i);
×
NEW
4046
          break;
×
NEW
4047
        case TSDB_DATA_TYPE_UTINYINT:
×
4048
        case TSDB_DATA_TYPE_USMALLINT:
4049
        case TSDB_DATA_TYPE_UINT:
4050
        case TSDB_DATA_TYPE_UBIGINT:
NEW
4051
          retCode = TEST_decimal128From_uint64_t(&v, pOutput->info.precision, pOutput->info.scale, pDefault->u);
×
NEW
4052
          break;
×
NEW
4053
        case TSDB_DATA_TYPE_FLOAT:
×
NEW
4054
          retCode = TEST_decimal128From_double(&v, pOutput->info.precision, pOutput->info.scale, pDefault->f);
×
NEW
4055
          break;
×
NEW
4056
        case TSDB_DATA_TYPE_DOUBLE:
×
NEW
4057
          retCode = TEST_decimal128From_double(&v, pOutput->info.precision, pOutput->info.scale, pDefault->d);
×
NEW
4058
          break;
×
NEW
4059
        case TSDB_DATA_TYPE_DECIMAL64: {
×
NEW
4060
          uint8_t inputPrecision = 0, inputScale = 0;
×
NEW
4061
          extractTypeFromTypeMod(pDefault->nType, inputTypeMod, &inputPrecision, &inputScale, NULL);
×
NEW
4062
          retCode = TEST_decimal128FromDecimal64((Decimal64*)&pDefault->i, inputPrecision, inputScale, &v,
×
NEW
4063
                                                 pOutput->info.precision, pOutput->info.scale);
×
NEW
4064
          break;
×
4065
        }
NEW
4066
        case TSDB_DATA_TYPE_DECIMAL: {
×
NEW
4067
          uint8_t inputPrecision = 0, inputScale = 0;
×
NEW
4068
          extractTypeFromTypeMod(pDefault->nType, inputTypeMod, &inputPrecision, &inputScale, NULL);
×
NEW
4069
          retCode = TEST_decimal128FromDecimal128((Decimal128*)pDefault->pz, inputPrecision, inputScale, &v,
×
NEW
4070
                                                  pOutput->info.precision, pOutput->info.scale);
×
NEW
4071
          break;
×
4072
        }
NEW
4073
        default:
×
NEW
4074
          retCode = TSDB_CODE_OPS_NOT_SUPPORT;
×
NEW
4075
          break;
×
4076
      }
4077

NEW
4078
      if (retCode == TSDB_CODE_SUCCESS) {
×
NEW
4079
        retCode = colDataSetVal(pOutput, pos, (const char*)&v, false);
×
4080
      }
NEW
4081
      break;
×
4082
    }
4083
    case TSDB_DATA_TYPE_GEOMETRY:
1,808✔
4084
      if (pDefault->pz == NULL) {
1,808✔
NEW
4085
        colDataSetNULL(pOutput, pos);
×
NEW
4086
        retCode = TSDB_CODE_SUCCESS;
×
NEW
4087
        break;
×
4088
      }
4089

4090
      if (pDefault->nType == TSDB_DATA_TYPE_GEOMETRY) {
1,808✔
NEW
4091
        retCode = colDataSetVal(pOutput, pos, pDefault->pz, false);
×
NEW
4092
        break;
×
4093
      }
4094

4095
      if (IS_STR_DATA_TYPE(pDefault->nType)) {
1,808✔
4096
#ifdef USE_GEOS
4097
        size_t         len = 0;
1,808✔
4098
        unsigned char* geom = NULL;
1,808✔
4099
        char*          output = NULL;
1,808✔
4100
        char*          inputWkt = NULL;
1,808✔
4101

4102
        retCode = initCtxGeomFromText();
1,808✔
4103
        if (retCode != TSDB_CODE_SUCCESS) {
1,808✔
NEW
4104
          break;
×
4105
        }
4106

4107
        if (pDefault->nType == TSDB_DATA_TYPE_NCHAR) {
1,808✔
NEW
4108
          int32_t charLen = varDataLen(pDefault->pz);
×
NEW
4109
          inputWkt = taosMemoryCalloc(1, charLen + TSDB_NCHAR_SIZE);
×
NEW
4110
          if (inputWkt == NULL) {
×
NEW
4111
            retCode = terrno;
×
NEW
4112
            break;
×
4113
          }
4114

NEW
4115
          int32_t cvtLen = taosUcs4ToMbs((TdUcs4*)varDataVal(pDefault->pz), charLen, inputWkt, NULL);
×
NEW
4116
          if (cvtLen < 0) {
×
NEW
4117
            taosMemoryFree(inputWkt);
×
NEW
4118
            retCode = TSDB_CODE_FAILED;
×
NEW
4119
            break;
×
4120
          }
NEW
4121
          inputWkt[cvtLen] = 0;
×
4122
        } else {
4123
          int32_t charLen = varDataLen(pDefault->pz);
1,808✔
4124
          inputWkt = taosMemoryCalloc(1, charLen + 1);
1,808✔
4125
          if (inputWkt == NULL) {
1,808✔
NEW
4126
            retCode = terrno;
×
NEW
4127
            break;
×
4128
          }
4129
          (void)memcpy(inputWkt, varDataVal(pDefault->pz), charLen);
1,808✔
4130
        }
4131

4132
        retCode = doGeomFromText(inputWkt, &geom, &len);
1,808✔
4133
        taosMemoryFree(inputWkt);
1,808✔
4134
        if (retCode != TSDB_CODE_SUCCESS) {
1,808✔
NEW
4135
          break;
×
4136
        }
4137

4138
        output = taosMemoryCalloc(1, len + VARSTR_HEADER_SIZE);
1,808✔
4139
        if (output == NULL) {
1,808✔
NEW
4140
          geosFreeBuffer(geom);
×
NEW
4141
          retCode = terrno;
×
NEW
4142
          break;
×
4143
        }
4144

4145
        (void)memcpy(output + VARSTR_HEADER_SIZE, geom, len);
1,808✔
4146
        varDataSetLen(output, len);
1,808✔
4147
        geosFreeBuffer(geom);
1,808✔
4148

4149
        retCode = colDataSetVal(pOutput, pos, output, false);
1,808✔
4150
        taosMemoryFree(output);
1,808✔
4151
        break;
1,808✔
4152
#else
4153
        retCode = TSDB_CODE_FUNC_FUNTION_PARA_TYPE;
4154
        break;
4155
#endif
4156
      }
4157

NEW
4158
      retCode = TSDB_CODE_FUNC_FUNTION_PARA_TYPE;
×
NEW
4159
      break;
×
4160
    case TSDB_DATA_TYPE_VARCHAR:
4,068✔
4161
    case TSDB_DATA_TYPE_VARBINARY:
4162
    case TSDB_DATA_TYPE_NCHAR:
4163
    case TSDB_DATA_TYPE_BLOB:
4164
      if (pDefault->pz == NULL) {
4,068✔
NEW
4165
        colDataSetNULL(pOutput, pos);
×
NEW
4166
        retCode = TSDB_CODE_SUCCESS;
×
NEW
4167
        break;
×
4168
      }
4169
      retCode = colDataSetVal(pOutput, pos, pDefault->pz, false);
4,068✔
4170
      break;
4,068✔
NEW
4171
    default:
×
NEW
4172
      colDataSetNULL(pOutput, pos);
×
NEW
4173
      retCode = TSDB_CODE_SUCCESS;
×
NEW
4174
      break;
×
4175
  }
4176

4177
  return retCode;
12,775,022✔
4178
}
4179

4180
static int32_t cloneLagLeadRowValue(const SLagLeadRowValue* pSrc, SLagLeadRowValue* pDst) {
11,133,956✔
4181
  pDst->isDataNull = pSrc->isDataNull;
11,133,956✔
4182
  pDst->pData = NULL;
11,133,956✔
4183
  pDst->dataLen = pSrc->dataLen;
11,133,956✔
4184
  pDst->block = pSrc->block;
11,133,956✔
4185
  pDst->rowIndex = pSrc->rowIndex;
11,133,956✔
4186

4187
  if (pSrc->isDataNull || pSrc->pData == NULL) {
11,133,956✔
4188
    return TSDB_CODE_SUCCESS;
904✔
4189
  }
4190

4191
  int32_t dataLen = pSrc->dataLen;
11,133,052✔
4192

4193
  if (dataLen <= 0) {
11,133,052✔
NEW
4194
    return TSDB_CODE_SUCCESS;
×
4195
  }
4196

4197
  pDst->pData = taosMemoryMalloc(dataLen);
11,133,052✔
4198
  if (pDst->pData == NULL) {
11,133,052✔
NEW
4199
    return terrno;
×
4200
  }
4201

4202
  (void)memcpy(pDst->pData, pSrc->pData, dataLen);
11,133,052✔
4203
  return TSDB_CODE_SUCCESS;
11,133,052✔
4204
}
4205

4206
static int32_t setLagLeadOutputFromValue(SqlFunctionCtx* pCtx, int32_t pos, SLagLeadRowValue* pValue) {
28,844,632✔
4207
  if (pValue->isDataNull) {
28,844,632✔
4208
    colDataSetNULL((SColumnInfoData*)pCtx->pOutput, pos);
2,712✔
4209
    return TSDB_CODE_SUCCESS;
2,712✔
4210
  }
4211

4212
  return colDataSetVal((SColumnInfoData*)pCtx->pOutput, pos, pValue->pData, false);
28,841,920✔
4213
}
4214

4215
static int32_t resolveLeadPendingRows(SqlFunctionCtx* pCtx, SLagLeadState* pState, SArray* pCurrValues) {
29,709✔
4216
  if (pState->pLeadPending == NULL || taosArrayGetSize(pState->pLeadPending) == 0) {
29,709✔
4217
    return TSDB_CODE_SUCCESS;
26,093✔
4218
  }
4219

4220
  int32_t code = TSDB_CODE_SUCCESS;
3,616✔
4221
  int32_t currSize = taosArrayGetSize(pCurrValues);
3,616✔
4222
  int32_t pendingSize = taosArrayGetSize(pState->pLeadPending);
3,616✔
4223
  SArray* pRemain = taosArrayInit(TMAX(pendingSize, 1), sizeof(SLeadPendingItem));
3,616✔
4224
  if (pRemain == NULL) {
3,616✔
NEW
4225
    return terrno;
×
4226
  }
4227

4228
  for (int32_t i = 0; i < pendingSize; ++i) {
7,411,444✔
4229
    SLeadPendingItem* pItem = taosArrayGet(pState->pLeadPending, i);
7,407,828✔
4230
    if (pItem == NULL) {
7,407,828✔
NEW
4231
      code = terrno;
×
NEW
4232
      goto cleanup;
×
4233
    }
4234

4235
    if (pItem->needIdx < currSize) {
7,407,828✔
4236
      SLagLeadRowValue* pTarget = taosArrayGet(pCurrValues, pItem->needIdx);
5,338,572✔
4237
      if (pTarget == NULL) {
5,338,572✔
NEW
4238
        code = terrno;
×
NEW
4239
        goto cleanup;
×
4240
      }
4241

4242
      code = setLagLeadOutputFromValue(pCtx, pItem->outputPos, pTarget);
5,338,572✔
4243
      if (code != TSDB_CODE_SUCCESS) {
5,338,572✔
NEW
4244
        goto cleanup;
×
4245
      }
4246
    } else {
4247
      pItem->needIdx -= currSize;
2,069,256✔
4248
      if (NULL == taosArrayPush(pRemain, pItem)) {
2,069,256✔
NEW
4249
        code = terrno;
×
NEW
4250
        goto cleanup;
×
4251
      }
4252
    }
4253
  }
4254

4255
  taosArrayDestroy(pState->pLeadPending);
3,616✔
4256
  pState->pLeadPending = pRemain;
3,616✔
4257

4258
cleanup:
3,616✔
4259
  if (code != TSDB_CODE_SUCCESS) {
3,616✔
NEW
4260
    taosArrayDestroy(pRemain);
×
4261
  }
4262

4263
  return code;
3,616✔
4264
}
4265

4266
static int32_t refreshLagTailValues(SLagLeadState* pState, SArray* pCurrValues, int64_t offset) {
22,491✔
4267
  int32_t currSize = taosArrayGetSize(pCurrValues);
22,491✔
4268
  if (offset <= 0 || currSize <= 0) {
22,491✔
NEW
4269
    return TSDB_CODE_SUCCESS;
×
4270
  }
4271

4272
  int32_t oldSize = (pState->pLagTail == NULL) ? 0 : taosArrayGetSize(pState->pLagTail);
22,491✔
4273
  int32_t keep = (int32_t)TMIN(offset, oldSize + currSize);
22,491✔
4274

4275
  SArray* pNewTail = taosArrayInit(TMAX(keep, 1), sizeof(SLagLeadRowValue));
22,491✔
4276
  if (pNewTail == NULL) {
22,491✔
NEW
4277
    return terrno;
×
4278
  }
4279

4280
  int32_t start = oldSize + currSize - keep;
22,491✔
4281
  for (int32_t idx = start; idx < oldSize + currSize; ++idx) {
11,156,447✔
4282
    SLagLeadRowValue* pSrc = NULL;
11,133,956✔
4283
    if (idx < oldSize) {
11,133,956✔
4284
      pSrc = taosArrayGet(pState->pLagTail, idx);
2,069,256✔
4285
    } else {
4286
      pSrc = taosArrayGet(pCurrValues, idx - oldSize);
9,064,700✔
4287
    }
4288

4289
    if (pSrc == NULL) {
11,133,956✔
NEW
4290
      cleanupLagLeadRowValueArray(pNewTail);
×
NEW
4291
      return terrno;
×
4292
    }
4293

4294
    SLagLeadRowValue newVal = {0};
11,133,956✔
4295
    int32_t code = cloneLagLeadRowValue(pSrc, &newVal);
11,133,956✔
4296
    if (code != TSDB_CODE_SUCCESS) {
11,133,956✔
NEW
4297
      cleanupLagLeadRowValueArray(pNewTail);
×
NEW
4298
      return code;
×
4299
    }
4300

4301
    if (NULL == taosArrayPush(pNewTail, &newVal)) {
11,133,956✔
NEW
4302
      if (newVal.pData != NULL) {
×
NEW
4303
        taosMemoryFree(newVal.pData);
×
4304
      }
NEW
4305
      cleanupLagLeadRowValueArray(pNewTail);
×
NEW
4306
      return terrno;
×
4307
    }
4308
  }
4309

4310
  if (pState->pLagTail != NULL) {
22,491✔
4311
    cleanupLagLeadRowValueArray(pState->pLagTail);
3,616✔
4312
  }
4313
  pState->pLagTail = pNewTail;
22,491✔
4314
  return TSDB_CODE_SUCCESS;
22,491✔
4315
}
4316

4317
static int32_t lagLeadFunctionByRowImpl(SArray* pCtxArray, bool isLead) {
49,291✔
4318
  int32_t code = TSDB_CODE_SUCCESS;
49,291✔
4319
  int32_t colNum = pCtxArray->size;
49,291✔
4320
  if (colNum == 0) {
49,291✔
NEW
4321
    return TSDB_CODE_SUCCESS;
×
4322
  }
4323

4324
  int32_t numOfElems = 0;
49,291✔
4325
  SArray* pRows = taosArrayInit_s(sizeof(SFuncInputRow), colNum);
49,291✔
4326
  if (NULL == pRows) {
49,291✔
NEW
4327
    return terrno;
×
4328
  }
4329

4330
  SArray* pValueArrays = taosArrayInit(colNum, sizeof(SArray*));
49,291✔
4331
  if (NULL == pValueArrays) {
49,291✔
NEW
4332
    code = terrno;
×
NEW
4333
    goto _exit;
×
4334
  }
4335

4336
  for (int32_t i = 0; i < colNum; ++i) {
101,491✔
4337
    SArray* pValues = taosArrayInit(32, sizeof(SLagLeadRowValue));
52,200✔
4338
    if (NULL == pValues) {
52,200✔
NEW
4339
      code = terrno;
×
NEW
4340
      goto _exit;
×
4341
    }
4342

4343
    if (NULL == taosArrayPush(pValueArrays, &pValues)) {
52,200✔
NEW
4344
      cleanupLagLeadRowValueArray(pValues);
×
NEW
4345
      code = terrno;
×
NEW
4346
      goto _exit;
×
4347
    }
4348
  }
4349

4350
  for (int32_t i = 0; i < colNum; ++i) {
101,491✔
4351
    SqlFunctionCtx* pCtx = *(SqlFunctionCtx**)taosArrayGet(pCtxArray, i);
52,200✔
4352
    if (NULL == pCtx) {
52,200✔
NEW
4353
      code = terrno;
×
NEW
4354
      goto _exit;
×
4355
    }
4356
    funcInputUpdate(pCtx);
52,200✔
4357
  }
4358

4359
  SqlFunctionCtx* pCtx0 = *(SqlFunctionCtx**)taosArrayGet(pCtxArray, 0);
49,291✔
4360
  SFuncInputRow*  pRow0 = (SFuncInputRow*)taosArrayGet(pRows, 0);
49,291✔
4361
  if (NULL == pCtx0 || NULL == pRow0) {
49,291✔
NEW
4362
    code = terrno;
×
NEW
4363
    goto _exit;
×
4364
  }
4365

4366
  int32_t startOffset = pCtx0->offset;
49,291✔
4367
  bool    result = false;
49,291✔
4368
  while (1) {
4369
    code = funcInputGetNextRow(pCtx0, pRow0, &result);
36,340,660✔
4370
    if (TSDB_CODE_SUCCESS != code) {
36,340,660✔
NEW
4371
      goto _exit;
×
4372
    }
4373
    if (!result) {
36,340,660✔
4374
      break;
49,291✔
4375
    }
4376

4377
    {
4378
      SArray*          pValues0 = *(SArray**)taosArrayGet(pValueArrays, 0);
36,291,369✔
4379
      SLagLeadRowValue rowValue = {0};
36,291,369✔
4380
      code = copyLagLeadRowValue(pCtx0, pRow0, &rowValue);
36,291,369✔
4381
      if (code != TSDB_CODE_SUCCESS) {
36,291,369✔
NEW
4382
        goto _exit;
×
4383
      }
4384

4385
      if (NULL == taosArrayPush(pValues0, &rowValue)) {
36,291,369✔
NEW
4386
        if (rowValue.pData != NULL) {
×
NEW
4387
          taosMemoryFree(rowValue.pData);
×
4388
        }
NEW
4389
        code = terrno;
×
NEW
4390
        goto _exit;
×
4391
      }
4392
    }
4393

4394
    for (int32_t i = 1; i < colNum; ++i) {
36,304,106✔
4395
      SqlFunctionCtx* pCtx = *(SqlFunctionCtx**)taosArrayGet(pCtxArray, i);
12,737✔
4396
      SFuncInputRow*  pRow = (SFuncInputRow*)taosArrayGet(pRows, i);
12,737✔
4397
      if (NULL == pCtx || NULL == pRow) {
12,737✔
NEW
4398
        code = terrno;
×
NEW
4399
        goto _exit;
×
4400
      }
4401

4402
      code = funcInputGetNextRow(pCtx, pRow, &result);
12,737✔
4403
      if (TSDB_CODE_SUCCESS != code) {
12,737✔
NEW
4404
        goto _exit;
×
4405
      }
4406
      if (!result) {
12,737✔
NEW
4407
        code = TSDB_CODE_QRY_EXECUTOR_INTERNAL_ERROR;
×
NEW
4408
        goto _exit;
×
4409
      }
4410

4411
      SArray*          pValues = *(SArray**)taosArrayGet(pValueArrays, i);
12,737✔
4412
      SLagLeadRowValue rowValue = {0};
12,737✔
4413
      code = copyLagLeadRowValue(pCtx, pRow, &rowValue);
12,737✔
4414
      if (code != TSDB_CODE_SUCCESS) {
12,737✔
NEW
4415
        goto _exit;
×
4416
      }
4417

4418
      if (NULL == taosArrayPush(pValues, &rowValue)) {
12,737✔
NEW
4419
        if (rowValue.pData != NULL) {
×
NEW
4420
          taosMemoryFree(rowValue.pData);
×
4421
        }
NEW
4422
        code = terrno;
×
NEW
4423
        goto _exit;
×
4424
      }
4425
    }
4426

4427
    ++numOfElems;
36,291,369✔
4428
  }
4429

4430
  for (int32_t i = 0; i < colNum; ++i) {
101,491✔
4431
    SqlFunctionCtx* pCtx = *(SqlFunctionCtx**)taosArrayGet(pCtxArray, i);
52,200✔
4432
    SArray*         pValues = *(SArray**)taosArrayGet(pValueArrays, i);
52,200✔
4433
    if (NULL == pCtx || NULL == pValues) {
52,200✔
NEW
4434
      code = terrno;
×
NEW
4435
      goto _exit;
×
4436
    }
4437

4438
    SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
52,200✔
4439
    SLagLeadState*       pState = GET_ROWCELL_INTERBUF(pResInfo);
52,200✔
4440
    if (pState == NULL) {
52,200✔
NEW
4441
      code = terrno;
×
NEW
4442
      goto _exit;
×
4443
    }
4444

4445
    int64_t offset = pCtx->param[1].param.i;
52,200✔
4446
    if (offset <= 0) {
52,200✔
NEW
4447
      code = TSDB_CODE_QRY_EXECUTOR_INTERNAL_ERROR;
×
NEW
4448
      goto _exit;
×
4449
    }
4450

4451
    if (isLead) {
52,200✔
4452
      if (pState->pLeadPending == NULL) {
29,709✔
4453
        pState->pLeadPending = taosArrayInit(8, sizeof(SLeadPendingItem));
26,093✔
4454
        if (pState->pLeadPending == NULL) {
26,093✔
NEW
4455
          code = terrno;
×
NEW
4456
          goto _exit;
×
4457
        }
4458
      }
4459

4460
      code = resolveLeadPendingRows(pCtx, pState, pValues);
29,709✔
4461
      if (code != TSDB_CODE_SUCCESS) {
29,709✔
NEW
4462
        goto _exit;
×
4463
      }
4464
    }
4465

4466
    for (int32_t rowIdx = 0; rowIdx < numOfElems; ++rowIdx) {
36,356,306✔
4467
      int32_t pos = startOffset + rowIdx;
36,304,106✔
4468
      SLagLeadRowValue* pCurRowValue = taosArrayGet(pValues, rowIdx);
36,304,106✔
4469
      if (pCurRowValue == NULL) {
36,304,106✔
NEW
4470
        code = terrno;
×
NEW
4471
        goto _exit;
×
4472
      }
4473

4474
      if (isLead) {
36,304,106✔
4475
        int64_t targetIdx = (int64_t)rowIdx + offset;
18,166,890✔
4476
        if (targetIdx < numOfElems) {
18,166,890✔
4477
          SLagLeadRowValue* pTargetRowValue = taosArrayGet(pValues, targetIdx);
9,094,972✔
4478
          if (pTargetRowValue == NULL) {
9,094,972✔
NEW
4479
            code = terrno;
×
NEW
4480
            goto _exit;
×
4481
          }
4482
          code = setLagLeadOutputFromValue(pCtx, pos, pTargetRowValue);
9,094,972✔
4483
        } else {
4484
          code = setLagLeadDefaultValue(pCtx, pos);
9,071,918✔
4485
          if (code == TSDB_CODE_SUCCESS) {
9,071,918✔
4486
            SLeadPendingItem pending = {.outputPos = pos, .needIdx = targetIdx - numOfElems};
9,071,918✔
4487
            if (NULL == taosArrayPush(pState->pLeadPending, &pending)) {
18,143,836✔
NEW
4488
              code = terrno;
×
4489
            }
4490
          }
4491
        }
4492
      } else {
4493
        int64_t targetIdx = (int64_t)rowIdx - offset;
18,137,216✔
4494
        if (targetIdx >= 0) {
18,137,216✔
4495
          SLagLeadRowValue* pTargetRowValue = taosArrayGet(pValues, targetIdx);
9,072,516✔
4496
          if (pTargetRowValue == NULL) {
9,072,516✔
NEW
4497
            code = terrno;
×
NEW
4498
            goto _exit;
×
4499
          }
4500
          code = setLagLeadOutputFromValue(pCtx, pos, pTargetRowValue);
9,072,516✔
4501
        } else {
4502
          int32_t tailSize = (pState->pLagTail == NULL) ? 0 : taosArrayGetSize(pState->pLagTail);
9,064,700✔
4503
          int64_t tailIdx = tailSize + targetIdx;
9,064,700✔
4504
          if (tailIdx >= 0 && tailIdx < tailSize) {
14,403,272✔
4505
            SLagLeadRowValue* pTargetRowValue = taosArrayGet(pState->pLagTail, tailIdx);
5,338,572✔
4506
            if (pTargetRowValue == NULL) {
5,338,572✔
NEW
4507
              code = terrno;
×
NEW
4508
              goto _exit;
×
4509
            }
4510
            code = setLagLeadOutputFromValue(pCtx, pos, pTargetRowValue);
5,338,572✔
4511
          } else {
4512
            code = setLagLeadDefaultValue(pCtx, pos);
3,726,128✔
4513
          }
4514
        }
4515
      }
4516

4517
      if (code != TSDB_CODE_SUCCESS) {
36,304,106✔
NEW
4518
        goto _exit;
×
4519
      }
4520

4521
      if (pCtx->subsidiaries.num > 0) {
36,304,106✔
4522
        code = appendSelectivityCols(pCtx, pCurRowValue->block, pCurRowValue->rowIndex, pos);
18,178,883✔
4523
        if (code != TSDB_CODE_SUCCESS) {
18,178,883✔
NEW
4524
          goto _exit;
×
4525
        }
4526
      }
4527
    }
4528

4529
    if (!isLead) {
52,200✔
4530
      code = refreshLagTailValues(pState, pValues, offset);
22,491✔
4531
      if (code != TSDB_CODE_SUCCESS) {
22,491✔
NEW
4532
        goto _exit;
×
4533
      }
4534
    }
4535
  }
4536

4537
_exit:
49,291✔
4538
  for (int32_t i = 0; i < colNum; ++i) {
101,491✔
4539
    SqlFunctionCtx* pCtx = *(SqlFunctionCtx**)taosArrayGet(pCtxArray, i);
52,200✔
4540
    if (!pCtx) {
52,200✔
NEW
4541
      break;
×
4542
    }
4543

4544
    if (!code) {
52,200✔
4545
      SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
52,200✔
4546
      pResInfo->numOfRes = numOfElems;
52,200✔
4547
    }
4548
  }
4549

4550
  if (pRows) {
49,291✔
4551
    taosArrayDestroy(pRows);
49,291✔
4552
    pRows = NULL;
49,291✔
4553
  }
4554

4555
  cleanupLagLeadValueArrays(pValueArrays);
49,291✔
4556

4557
  return code;
49,291✔
4558
}
4559

4560
int32_t lagFunctionByRow(SArray* pCtxArray) {
21,638✔
4561
  return lagLeadFunctionByRowImpl(pCtxArray, false);
21,638✔
4562
}
4563

4564
bool getLeadFuncEnv(SFunctionNode* UNUSED_PARAM(pFunc), SFuncExecEnv* pEnv) {
25,692✔
4565
  pEnv->calcMemSize = sizeof(SLagLeadState);
25,692✔
4566
  return true;
25,692✔
4567
}
4568

4569
int32_t leadFunctionSetup(SqlFunctionCtx* pCtx, SResultRowEntryInfo* pResInfo) {
55,401✔
4570
  if (pResInfo->initialized) {
55,401✔
4571
    return TSDB_CODE_SUCCESS;
28,404✔
4572
  }
4573
  if (TSDB_CODE_SUCCESS != functionSetup(pCtx, pResInfo)) {
26,997✔
NEW
4574
    return TSDB_CODE_FUNC_SETUP_ERROR;
×
4575
  }
4576

4577
  SLagLeadState* pState = GET_ROWCELL_INTERBUF(pResInfo);
26,997✔
4578
  if (pState != NULL) {
26,997✔
4579
    pState->pLagTail = NULL;
26,997✔
4580
    pState->pLeadPending = NULL;
26,997✔
4581
  }
4582

4583
  return TSDB_CODE_SUCCESS;
26,997✔
4584
}
4585

4586
int32_t leadFunction(SqlFunctionCtx* UNUSED_PARAM(pCtx)) { return TSDB_CODE_SUCCESS; }
29,709✔
4587

4588
int32_t leadFunctionByRow(SArray* pCtxArray) {
27,653✔
4589
  return lagLeadFunctionByRowImpl(pCtxArray, true);
27,653✔
4590
}
4591

4592
void lagLeadFunctionCleanupExt(SqlFunctionCtx* pCtx) {
46,776✔
4593
  if (pCtx == NULL || pCtx->resultInfo == NULL) {
46,776✔
NEW
4594
    return;
×
4595
  }
4596

4597
  SLagLeadState* pState = GET_ROWCELL_INTERBUF(pCtx->resultInfo);
46,776✔
4598
  if (pState == NULL) {
46,776✔
NEW
4599
    return;
×
4600
  }
4601

4602
  if (pState->pLagTail != NULL) {
46,776✔
4603
    cleanupLagLeadRowValueArray(pState->pLagTail);
18,875✔
4604
    pState->pLagTail = NULL;
18,875✔
4605
  }
4606

4607
  if (pState->pLeadPending != NULL) {
46,776✔
4608
    taosArrayDestroy(pState->pLeadPending);
26,093✔
4609
    pState->pLeadPending = NULL;
26,093✔
4610
  }
4611
}
4612

4613
bool getFillforwardFuncEnv(SFunctionNode* UNUSED_PARAM(pFunc), SFuncExecEnv* pEnv) {
36,423✔
4614
  pEnv->calcMemSize = sizeof(SFillforwardInfo);
36,423✔
4615
  return true;
36,423✔
4616
}
4617

4618
int32_t fillforwardFunctionSetup(SqlFunctionCtx* pCtx, SResultRowEntryInfo* pResInfo) {
75,450✔
4619
  if (pResInfo->initialized) {
75,450✔
4620
    return TSDB_CODE_SUCCESS;
36,423✔
4621
  }
4622
  if (TSDB_CODE_SUCCESS != functionSetup(pCtx, pResInfo)) {
39,027✔
4623
    return TSDB_CODE_FUNC_SETUP_ERROR;
×
4624
  }
4625
  SFillforwardInfo* pFillforwardInfo = GET_ROWCELL_INTERBUF(pResInfo);
39,027✔
4626
  pFillforwardInfo->nonnull = false;
39,027✔
4627

4628
  return TSDB_CODE_SUCCESS;
39,027✔
4629
}
4630

4631
int32_t fillforwardFunction(SqlFunctionCtx* pCtx) { return TSDB_CODE_SUCCESS; }
39,027✔
4632

4633
static int32_t doHandleFillforward(SFillforwardInfo* pFillforwardInfo, int32_t type, SColumnInfoData* pOutput, int32_t pos) {
126,596✔
4634
  if (!pFillforwardInfo->nonnull) {
126,596✔
4635
    colDataSetNULL(pOutput, pos);
14,322✔
4636

4637
    return TSDB_CODE_SUCCESS;
14,322✔
4638
  }
4639

4640
  switch (type) {
112,274✔
4641
    case TSDB_DATA_TYPE_BOOL:
54,118✔
4642
    case TSDB_DATA_TYPE_UTINYINT:
4643
    case TSDB_DATA_TYPE_TINYINT:
4644
    case TSDB_DATA_TYPE_USMALLINT:
4645
    case TSDB_DATA_TYPE_SMALLINT:
4646
    case TSDB_DATA_TYPE_UINT:
4647
    case TSDB_DATA_TYPE_INT:
4648
    case TSDB_DATA_TYPE_UBIGINT:
4649
    case TSDB_DATA_TYPE_BIGINT:
4650
    case TSDB_DATA_TYPE_TIMESTAMP:
4651
      colDataSetInt64(pOutput, pos, &pFillforwardInfo->v);
54,118✔
4652
      break;
54,118✔
4653
    case TSDB_DATA_TYPE_FLOAT:
20,832✔
4654
      colDataSetFloat(pOutput, pos, &pFillforwardInfo->fv);
20,832✔
4655
      break;
20,832✔
4656
    case TSDB_DATA_TYPE_DOUBLE:
23,436✔
4657
      colDataSetDouble(pOutput, pos, &pFillforwardInfo->dv);
23,436✔
4658
      break;
23,436✔
4659
    case TSDB_DATA_TYPE_DECIMAL64:
4,774✔
4660
      return colDataSetVal(pOutput, pos, (const char*)&pFillforwardInfo->v, false);
4,774✔
4661
    case TSDB_DATA_TYPE_DECIMAL:
×
4662
      return colDataSetVal(pOutput, pos, (void*)pFillforwardInfo->dec, false);
×
4663
    case TSDB_DATA_TYPE_VARCHAR:
9,114✔
4664
    case TSDB_DATA_TYPE_VARBINARY:
4665
    case TSDB_DATA_TYPE_NCHAR:
4666
      return colDataSetVal(pOutput, pos, (void*)pFillforwardInfo->str, false);
9,114✔
4667
    default:
×
4668
      return TSDB_CODE_FUNC_FUNTION_PARA_TYPE;
×
4669
  }
4670

4671
  return TSDB_CODE_SUCCESS;
98,386✔
4672
}
4673

4674
static int32_t setFillforwardResult(SqlFunctionCtx* pCtx, SFuncInputRow* pRow, int32_t pos) {
126,596✔
4675
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
126,596✔
4676
  SFillforwardInfo*            pFillforwardInfo = GET_ROWCELL_INTERBUF(pResInfo);
126,596✔
4677

4678
  SInputColumnInfoData* pInput = &pCtx->input;
126,596✔
4679
  SColumnInfoData*      pInputCol = pInput->pData[0];
126,596✔
4680
  int8_t                inputType = pInputCol->info.type;
126,596✔
4681
  SColumnInfoData*      pOutput = (SColumnInfoData*)pCtx->pOutput;
126,596✔
4682
  int32_t               code = TSDB_CODE_SUCCESS;
126,596✔
4683

4684
  code = doHandleFillforward(pFillforwardInfo, inputType, pOutput, pos);
126,596✔
4685
  if (code != TSDB_CODE_SUCCESS) {
126,596✔
4686
    return code;
×
4687
  }
4688

4689
  // handle selectivity
4690
  if (pCtx->subsidiaries.num > 0) {
126,596✔
4691
    code = appendSelectivityCols(pCtx, pRow->block, pRow->rowIndex, pos);
34,588✔
4692
    if (code != TSDB_CODE_SUCCESS) {
34,588✔
4693
      return code;
×
4694
    }
4695
  }
4696

4697
  return TSDB_CODE_SUCCESS;
126,596✔
4698
}
4699

4700
int32_t fillforwardFunctionByRow(SArray* pCtxArray) {
11,251✔
4701
  int32_t code = TSDB_CODE_SUCCESS;
11,251✔
4702
  int     fillforwardColNum = pCtxArray->size;
11,251✔
4703
  if (fillforwardColNum == 0) {
11,251✔
4704
    return TSDB_CODE_SUCCESS;
×
4705
  }
4706
  int32_t numOfElems = 0;
11,251✔
4707

4708
  SArray* pRows = taosArrayInit_s(sizeof(SFuncInputRow), fillforwardColNum);
11,251✔
4709
  if (NULL == pRows) {
11,251✔
4710
    return terrno;
×
4711
  }
4712

4713
  for (int i = 0; i < fillforwardColNum; ++i) {
50,278✔
4714
    SqlFunctionCtx* pCtx = *(SqlFunctionCtx**)taosArrayGet(pCtxArray, i);
39,027✔
4715
    if (NULL == pCtx) {
39,027✔
4716
      code = terrno;
×
4717
      goto _exit;
×
4718
    }
4719
    funcInputUpdate(pCtx);
39,027✔
4720
  }
4721

4722
  SqlFunctionCtx* pCtx0 = *(SqlFunctionCtx**)taosArrayGet(pCtxArray, 0);
11,251✔
4723
  SFuncInputRow*  pRow0 = (SFuncInputRow*)taosArrayGet(pRows, 0);
11,251✔
4724
  if (NULL == pCtx0 || NULL == pRow0) {
11,251✔
4725
    code = terrno;
×
4726
    goto _exit;
×
4727
  }
4728
  int32_t startOffset = pCtx0->offset;
11,251✔
4729
  bool    result = false;
11,251✔
4730
  while (1) {
34,588✔
4731
    code = funcInputGetNextRow(pCtx0, pRow0, &result);
45,839✔
4732
    if (TSDB_CODE_SUCCESS != code) {
45,839✔
4733
      goto _exit;
×
4734
    }
4735
    if (!result) {
45,839✔
4736
      break;
10,817✔
4737
    }
4738

4739
    for (int i = 1; i < fillforwardColNum; ++i) {
127,030✔
4740
      SqlFunctionCtx* pCtx = *(SqlFunctionCtx**)taosArrayGet(pCtxArray, i);
92,008✔
4741
      SFuncInputRow*  pRow = (SFuncInputRow*)taosArrayGet(pRows, i);
92,008✔
4742
      if (NULL == pCtx || NULL == pRow) {
92,008✔
4743
        code = terrno;
×
4744
        goto _exit;
×
4745
      }
4746
      code = funcInputGetNextRow(pCtx, pRow, &result);
92,008✔
4747
      if (TSDB_CODE_SUCCESS != code) {
92,008✔
4748
        goto _exit;
×
4749
      }
4750
      if (!result) {
92,008✔
4751
        // rows are not equal
4752
        code = TSDB_CODE_QRY_EXECUTOR_INTERNAL_ERROR;
×
4753
        goto _exit;
×
4754
      }
4755
    }
4756

4757
    int32_t pos = startOffset + numOfElems;
35,022✔
4758

4759
    for (int i = 0; i < fillforwardColNum; ++i) {
161,618✔
4760
      SqlFunctionCtx* pCtx = *(SqlFunctionCtx**)taosArrayGet(pCtxArray, i);
127,030✔
4761
      SFuncInputRow*  pRow = (SFuncInputRow*)taosArrayGet(pRows, i);
127,030✔
4762
      if (NULL == pCtx || NULL == pRow) {
127,030✔
4763
        code = terrno;
×
4764
        goto _exit;
×
4765
      }
4766

4767
      if (!colDataIsNull_s(pCtx->input.pData[0], pCtx->rowIter.rowIndex - 1)) {
254,060✔
4768
        SResultRowEntryInfo*  pResInfo = GET_RES_INFO(pCtx);
77,988✔
4769
        SFillforwardInfo*             pFillforwardInfo = GET_ROWCELL_INTERBUF(pResInfo);
77,988✔
4770
        SInputColumnInfoData* pInput = &pCtx->input;
77,988✔
4771
        SColumnInfoData*      pInputCol = pInput->pData[0];
77,988✔
4772
        int8_t                inputType = pInputCol->info.type;
77,988✔
4773

4774
        char* pv = pRow->pData;
77,988✔
4775
        switch (inputType) {
77,988✔
4776
          case TSDB_DATA_TYPE_BOOL:
15,190✔
4777
            pFillforwardInfo->v = *(bool*)pv ? 1 : 0;
15,190✔
4778
            break;
15,190✔
4779
          case TSDB_DATA_TYPE_UTINYINT:
434✔
4780
          case TSDB_DATA_TYPE_TINYINT:
4781
            pFillforwardInfo->v = *(int8_t*)pv;
434✔
4782
            break;
434✔
4783
          case TSDB_DATA_TYPE_UINT:
22,436✔
4784
          case TSDB_DATA_TYPE_INT:
4785
            pFillforwardInfo->v = *(int32_t*)pv;
22,436✔
4786
            break;
22,436✔
4787
          case TSDB_DATA_TYPE_USMALLINT:
434✔
4788
          case TSDB_DATA_TYPE_SMALLINT:
4789
            pFillforwardInfo->v = *(int16_t*)pv;
434✔
4790
            break;
434✔
4791
          case TSDB_DATA_TYPE_TIMESTAMP:
434✔
4792
          case TSDB_DATA_TYPE_UBIGINT:
4793
          case TSDB_DATA_TYPE_BIGINT:
4794
            pFillforwardInfo->v = *(int64_t*)pv;
434✔
4795
            break;
434✔
4796
          case TSDB_DATA_TYPE_FLOAT:
15,190✔
4797
            pFillforwardInfo->fv = *(float*)pv;
15,190✔
4798
            break;
15,190✔
4799
          case TSDB_DATA_TYPE_DOUBLE:
16,926✔
4800
            pFillforwardInfo->dv = *(double*)pv;
16,926✔
4801
            break;
16,926✔
4802
          case TSDB_DATA_TYPE_DECIMAL64:
2,604✔
4803
            DECIMAL64_SET_VALUE((Decimal64*)&pFillforwardInfo->v, *(int64_t*)pv);
2,604✔
4804
            break;
2,604✔
4805
          case TSDB_DATA_TYPE_DECIMAL:
×
4806
            DECIMAL128_CLONE((Decimal128*)pFillforwardInfo->dec, (Decimal128*)pv);
×
4807
            break;
×
4808
          case TSDB_DATA_TYPE_VARCHAR:
3,906✔
4809
          case TSDB_DATA_TYPE_VARBINARY:
4810
          case TSDB_DATA_TYPE_NCHAR: {
4811
            if (!pFillforwardInfo->nonnull) {
3,906✔
4812
              pFillforwardInfo->str = taosMemoryMalloc(pInputCol->info.bytes);
2,604✔
4813
              if (!pFillforwardInfo->str) {
2,604✔
4814
                code = terrno;
×
4815
                goto _exit;
×
4816
              }
4817
            }
4818

4819
            (void)memcpy(pFillforwardInfo->str, pv, varDataTLen(pv));
3,906✔
4820
          } break;
3,906✔
4821
          default: {
434✔
4822
            code = TSDB_CODE_FUNC_FUNTION_PARA_TYPE;
434✔
4823
            goto _exit;
434✔
4824
          }
4825
        }
4826

4827
        if (!pFillforwardInfo->nonnull) {
77,554✔
4828
          pFillforwardInfo->nonnull = true;
38,159✔
4829
        }
4830
      }
4831

4832
      code = setFillforwardResult(pCtx, pRow, pos);
126,596✔
4833
      if (code) {
126,596✔
4834
        goto _exit;
×
4835
      }
4836
    }
4837

4838
    ++numOfElems;
34,588✔
4839
  }
4840

4841
_exit:
11,251✔
4842
  for (int i = 0; i < fillforwardColNum; ++i) {
50,278✔
4843
    SqlFunctionCtx* pCtx = *(SqlFunctionCtx**)taosArrayGet(pCtxArray, i);
39,027✔
4844
    if (!pCtx) {
39,027✔
4845
      break;
×
4846
    }
4847

4848
    SResultRowEntryInfo*  pResInfo = GET_RES_INFO(pCtx);
39,027✔
4849
    SFillforwardInfo*             pRes = GET_ROWCELL_INTERBUF(pResInfo);
39,027✔
4850
    SInputColumnInfoData* pInput = &pCtx->input;
39,027✔
4851
    SColumnInfoData*      pInputCol = pInput->pData[0];
39,027✔
4852

4853
    if (IS_VAR_DATA_TYPE(pInputCol->info.type) && pRes->nonnull) {
39,027✔
4854
      taosMemoryFree(pRes->str);
2,604✔
4855
    }
4856

4857
    if (!code) {
39,027✔
4858
      pResInfo->numOfRes = numOfElems;
38,593✔
4859
    }
4860
  }
4861

4862
  if (pRows) {
11,251✔
4863
    taosArrayDestroy(pRows);
11,251✔
4864
    pRows = NULL;
11,251✔
4865
  }
4866
  return code;
11,251✔
4867
}
4868

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

4871
bool getTopBotFuncEnv(SFunctionNode* pFunc, SFuncExecEnv* pEnv) {
2,163,381✔
4872
  SValueNode* pkNode = (SValueNode*)nodesListGetNode(pFunc->pParameterList, 1);
2,163,381✔
4873
  pEnv->calcMemSize = sizeof(STopBotRes) + pkNode->datum.i * sizeof(STopBotResItem);
2,163,822✔
4874
  return true;
2,163,822✔
4875
}
4876

4877
int32_t topBotFunctionSetup(SqlFunctionCtx* pCtx, SResultRowEntryInfo* pResInfo) {
7,750,591✔
4878
  if (pResInfo->initialized) {
7,750,591✔
4879
    return TSDB_CODE_SUCCESS;
×
4880
  }
4881
  if (TSDB_CODE_SUCCESS != functionSetup(pCtx, pResInfo)) {
7,750,591✔
4882
    return TSDB_CODE_FUNC_SETUP_ERROR;
×
4883
  }
4884

4885
  STopBotRes*           pRes = GET_ROWCELL_INTERBUF(pResInfo);
7,749,635✔
4886
  SInputColumnInfoData* pInput = &pCtx->input;
7,750,057✔
4887

4888
  pRes->maxSize = pCtx->param[1].param.i;
7,750,057✔
4889

4890
  pRes->nullTupleSaved = false;
7,750,591✔
4891
  pRes->nullTuplePos.pageId = -1;
7,750,591✔
4892
  return TSDB_CODE_SUCCESS;
7,751,033✔
4893
}
4894

4895
static STopBotRes* getTopBotOutputInfo(SqlFunctionCtx* pCtx) {
2,127,354,350✔
4896
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
2,127,354,350✔
4897
  STopBotRes*          pRes = GET_ROWCELL_INTERBUF(pResInfo);
2,127,364,484✔
4898
  pRes->pItems = (STopBotResItem*)((char*)pRes + sizeof(STopBotRes));
2,127,379,008✔
4899

4900
  return pRes;
2,127,811,357✔
4901
}
4902

4903
static int32_t doAddIntoResult(SqlFunctionCtx* pCtx, void* pData, int32_t rowIndex, SSDataBlock* pSrcBlock,
4904
                               uint16_t type, uint64_t uid, SResultRowEntryInfo* pEntryInfo, bool isTopQuery);
4905

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

4908
int32_t topFunction(SqlFunctionCtx* pCtx) {
9,001,176✔
4909
  int32_t              numOfElems = 0;
9,001,176✔
4910
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
9,001,176✔
4911

4912
  SInputColumnInfoData* pInput = &pCtx->input;
9,001,176✔
4913
  SColumnInfoData*      pCol = pInput->pData[0];
9,001,176✔
4914

4915
  STopBotRes* pRes = getTopBotOutputInfo(pCtx);
9,001,816✔
4916
  pRes->type = pInput->pData[0]->info.type;
9,000,754✔
4917

4918
  int32_t start = pInput->startRowIndex;
9,001,394✔
4919
  for (int32_t i = start; i < pInput->numOfRows + start; ++i) {
1,259,594,424✔
4920
    if (pCol->hasNull && colDataIsNull_f(pCol, i)) {
1,252,368,610✔
4921
      continue;
2,361,050✔
4922
    }
4923

4924
    numOfElems++;
1,248,888,851✔
4925
    char*   data = colDataGetData(pCol, i);
1,248,888,851✔
4926
    int32_t code = doAddIntoResult(pCtx, data, i, pCtx->pSrcBlock, pRes->type, pInput->uid, pResInfo, true);
1,252,982,357✔
4927
    if (code != TSDB_CODE_SUCCESS) {
1,248,231,558✔
4928
      return code;
×
4929
    }
4930
  }
4931

4932
  if (numOfElems == 0 && pCtx->subsidiaries.num > 0 && !pRes->nullTupleSaved) {
9,001,282✔
4933
    int32_t code = saveTupleData(pCtx, pInput->startRowIndex, pCtx->pSrcBlock, &pRes->nullTuplePos);
6,828✔
4934
    if (code != TSDB_CODE_SUCCESS) {
6,828✔
4935
      return code;
×
4936
    }
4937
    pRes->nullTupleSaved = true;
6,828✔
4938
  }
4939
  return TSDB_CODE_SUCCESS;
9,001,282✔
4940
}
4941

4942
int32_t bottomFunction(SqlFunctionCtx* pCtx) {
3,235,548✔
4943
  int32_t              numOfElems = 0;
3,235,548✔
4944
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
3,235,548✔
4945

4946
  SInputColumnInfoData* pInput = &pCtx->input;
3,235,990✔
4947
  SColumnInfoData*      pCol = pInput->pData[0];
3,235,990✔
4948

4949
  STopBotRes* pRes = getTopBotOutputInfo(pCtx);
3,235,990✔
4950
  pRes->type = pInput->pData[0]->info.type;
3,235,990✔
4951

4952
  int32_t start = pInput->startRowIndex;
3,235,548✔
4953
  for (int32_t i = start; i < pInput->numOfRows + start; ++i) {
861,552,245✔
4954
    if (pCol->hasNull && colDataIsNull_f(pCol, i)) {
858,316,950✔
4955
      continue;
2,757,436✔
4956
    }
4957

4958
    numOfElems++;
855,764,165✔
4959
    char*   data = colDataGetData(pCol, i);
855,764,165✔
4960
    int32_t code = doAddIntoResult(pCtx, data, i, pCtx->pSrcBlock, pRes->type, pInput->uid, pResInfo, false);
856,595,729✔
4961
    if (code != TSDB_CODE_SUCCESS) {
855,559,261✔
4962
      return code;
×
4963
    }
4964
  }
4965

4966
  if (numOfElems == 0 && pCtx->subsidiaries.num > 0 && !pRes->nullTupleSaved) {
3,235,990✔
4967
    int32_t code = saveTupleData(pCtx, pInput->startRowIndex, pCtx->pSrcBlock, &pRes->nullTuplePos);
12,644✔
4968
    if (code != TSDB_CODE_SUCCESS) {
12,644✔
4969
      return code;
×
4970
    }
4971
    pRes->nullTupleSaved = true;
12,644✔
4972
  }
4973

4974
  return TSDB_CODE_SUCCESS;
3,235,548✔
4975
}
4976

4977
static int32_t topBotResComparFn(const void* p1, const void* p2, const void* param) {
499,813,715✔
4978
  uint16_t type = *(uint16_t*)param;
499,813,715✔
4979

4980
  STopBotResItem* val1 = (STopBotResItem*)p1;
499,814,691✔
4981
  STopBotResItem* val2 = (STopBotResItem*)p2;
499,814,691✔
4982

4983
  if (IS_SIGNED_NUMERIC_TYPE(type)) {
499,814,691✔
4984
    if (val1->v.i == val2->v.i) {
324,506,413✔
4985
      return 0;
56,391,520✔
4986
    }
4987

4988
    return (val1->v.i > val2->v.i) ? 1 : -1;
268,156,861✔
4989
  } else if (IS_UNSIGNED_NUMERIC_TYPE(type)) {
175,308,278✔
4990
    if (val1->v.u == val2->v.u) {
85,102,527✔
4991
      return 0;
18,265,833✔
4992
    }
4993

4994
    return (val1->v.u > val2->v.u) ? 1 : -1;
66,900,026✔
4995
  } else if (TSDB_DATA_TYPE_FLOAT == type) {
90,205,963✔
4996
    if (val1->v.f == val2->v.f) {
1,555,703✔
4997
      return 0;
27,783✔
4998
    }
4999

5000
    return (val1->v.f > val2->v.f) ? 1 : -1;
1,527,920✔
5001
  }
5002

5003
  if (val1->v.d == val2->v.d) {
88,650,260✔
5004
    return 0;
4,851✔
5005
  }
5006

5007
  return (val1->v.d > val2->v.d) ? 1 : -1;
88,651,295✔
5008
}
5009

5010
int32_t doAddIntoResult(SqlFunctionCtx* pCtx, void* pData, int32_t rowIndex, SSDataBlock* pSrcBlock, uint16_t type,
2,106,085,752✔
5011
                        uint64_t uid, SResultRowEntryInfo* pEntryInfo, bool isTopQuery) {
5012
  STopBotRes* pRes = getTopBotOutputInfo(pCtx);
2,106,085,752✔
5013
  int32_t     code = TSDB_CODE_SUCCESS;
2,106,906,603✔
5014

5015
  SVariant val = {0};
2,106,906,603✔
5016
  TAOS_CHECK_RETURN(taosVariantCreateFromBinary(&val, pData, tDataTypes[type].bytes, type));
2,107,447,629✔
5017

5018
  STopBotResItem* pItems = pRes->pItems;
2,104,250,623✔
5019

5020
  // not full yet
5021
  if (pEntryInfo->numOfRes < pRes->maxSize) {
2,104,597,133✔
5022
    STopBotResItem* pItem = &pItems[pEntryInfo->numOfRes];
45,090,873✔
5023
    pItem->v = val;
45,090,853✔
5024
    pItem->uid = uid;
45,090,853✔
5025

5026
    // save the data of this tuple
5027
    if (pCtx->subsidiaries.num > 0) {
45,091,829✔
5028
      code = saveTupleData(pCtx, rowIndex, pSrcBlock, &pItem->tuplePos);
12,450,499✔
5029
      if (code != TSDB_CODE_SUCCESS) {
12,450,057✔
5030
        return code;
×
5031
      }
5032
    }
5033
#ifdef BUF_PAGE_DEBUG
5034
    qDebug("page_saveTuple i:%d, item:%p,pageId:%d, offset:%d\n", pEntryInfo->numOfRes, pItem, pItem->tuplePos.pageId,
5035
           pItem->tuplePos.offset);
5036
#endif
5037
    // allocate the buffer and keep the data of this row into the new allocated buffer
5038
    pEntryInfo->numOfRes++;
45,091,387✔
5039
    code = taosheapsort((void*)pItems, sizeof(STopBotResItem), pEntryInfo->numOfRes, (const void*)&type,
45,092,027✔
5040
                        topBotResComparFn, !isTopQuery);
45,092,047✔
5041
    if (code != TSDB_CODE_SUCCESS) {
45,090,238✔
5042
      return code;
×
5043
    }
5044
  } else {  // replace the minimum value in the result
5045
    if ((isTopQuery && ((IS_SIGNED_NUMERIC_TYPE(type) && val.i > pItems[0].v.i) ||
2,059,795,986✔
5046
                        (IS_UNSIGNED_NUMERIC_TYPE(type) && val.u > pItems[0].v.u) ||
1,196,764,317✔
5047
                        (TSDB_DATA_TYPE_FLOAT == type && val.f > pItems[0].v.f) ||
1,189,294,216✔
5048
                        (TSDB_DATA_TYPE_DOUBLE == type && val.d > pItems[0].v.d))) ||
1,189,213,213✔
5049
        (!isTopQuery && ((IS_SIGNED_NUMERIC_TYPE(type) && val.i < pItems[0].v.i) ||
2,026,284,650✔
5050
                         (IS_UNSIGNED_NUMERIC_TYPE(type) && val.u < pItems[0].v.u) ||
843,842,196✔
5051
                         (TSDB_DATA_TYPE_FLOAT == type && val.f < pItems[0].v.f) ||
842,688,484✔
5052
                         (TSDB_DATA_TYPE_DOUBLE == type && val.d < pItems[0].v.d)))) {
842,722,530✔
5053
      // replace the old data and the coresponding tuple data
5054
      STopBotResItem* pItem = &pItems[0];
37,243,047✔
5055
      pItem->v = val;
37,243,047✔
5056
      pItem->uid = uid;
37,615,507✔
5057

5058
      // save the data of this tuple by over writing the old data
5059
      if (pCtx->subsidiaries.num > 0) {
37,614,973✔
5060
        code = updateTupleData(pCtx, rowIndex, pSrcBlock, &pItem->tuplePos);
20,031,059✔
5061
        if (code != TSDB_CODE_SUCCESS) {
20,030,215✔
5062
          return code;
×
5063
        }
5064
      }
5065
#ifdef BUF_PAGE_DEBUG
5066
      qDebug("page_copyTuple pageId:%d, offset:%d", pItem->tuplePos.pageId, pItem->tuplePos.offset);
5067
#endif
5068
      code = taosheapadjust((void*)pItems, sizeof(STopBotResItem), 0, pEntryInfo->numOfRes - 1, (const void*)&type,
37,614,129✔
5069
                            topBotResComparFn, NULL, !isTopQuery);
37,614,129✔
5070
      if (code != TSDB_CODE_SUCCESS) {
37,610,481✔
5071
        return code;
×
5072
      }
5073
    }
5074
  }
5075

5076
  return TSDB_CODE_SUCCESS;
2,105,058,125✔
5077
}
5078

5079

5080
bool hasNullFunc(  SColumnInfoData *pData,   SColumnDataAgg *pAgg, int32_t startIdx, int64_t rows) {
×
5081
  if (NULL != pAgg) {
×
5082
    return pAgg->numOfNull > 0 ? true : false;
×
5083
  }
5084

5085
  if (!pData->hasNull) {
×
5086
    return false;
×
5087
  }
5088

5089
  int64_t endIdx = startIdx + rows;
×
5090
  for (int64_t i = startIdx; i < endIdx; ++i) {
×
5091
    if (colDataIsNull_s(pData, i)) {
×
5092
      return true;
×
5093
    }
5094
  }
5095

5096
  return false;
×
5097
}
5098

5099

5100
/*
5101
 * +------------------------------------+--------------+--------------+
5102
 * |            null bitmap             |              |              |
5103
 * |(n columns, one bit for each column)| src column #1| src column #2|
5104
 * +------------------------------------+--------------+--------------+
5105
 */
5106
int32_t serializeTupleData(SqlFunctionCtx* pCtx, const SSDataBlock* pSrcBlock, int32_t rowIndex, SSubsidiaryResInfo* pSubsidiaryies,
116,576,588✔
5107
                           char* buf, char** res) {
5108
  char* nullList = buf;
116,576,588✔
5109
  char* pStart = (char*)(nullList + sizeof(bool) * pSubsidiaryies->num);
116,576,588✔
5110

5111
  int32_t offset = 0;
116,576,513✔
5112
  for (int32_t i = 0; i < pSubsidiaryies->num; ++i) {
363,110,871✔
5113
    SqlFunctionCtx* pc = pSubsidiaryies->pCtx[i];
246,535,048✔
5114

5115
    // group_key function has its own process function
5116
    // do not process there
5117
    if (fmIsGroupKeyFunc(pc->functionId)) {
246,531,135✔
5118
      continue;
×
5119
    }
5120

5121
    if (fmIsSelectValueFunc(pc->functionId)) {
246,528,004✔
5122
      SFunctParam* pFuncParam = &pc->pExpr->base.pParam[0];
246,532,599✔
5123
      int32_t      srcSlotId = pFuncParam->pCol->slotId;
246,531,059✔
5124

5125
      SColumnInfoData* pCol = taosArrayGet(pSrcBlock->pDataBlock, srcSlotId);
246,532,324✔
5126
      if (NULL == pCol) {
246,529,750✔
5127
        return TSDB_CODE_OUT_OF_RANGE;
×
5128
      }
5129
      if ((nullList[i] = colDataIsNull_s(pCol, rowIndex)) == true) {
493,057,801✔
5130
        offset += pCol->info.bytes;
64,865,210✔
5131
        continue;
64,865,210✔
5132
      }
5133

5134
      char* p = colDataGetData(pCol, rowIndex);
181,663,708✔
5135
      if (IS_VAR_DATA_TYPE(pCol->info.type)) {
181,670,279✔
5136
        int32_t bytes = calcStrBytesByType(pCol->info.type, p);
8,669,467✔
5137
        (void)memcpy(pStart + offset, p, bytes);
8,669,893✔
5138
      } else {
5139
        (void)memcpy(pStart + offset, p, pCol->info.bytes);
172,995,037✔
5140
      }
5141

5142
      offset += pCol->info.bytes;
181,667,664✔
5143
      continue;
181,671,116✔
5144
    }
5145
  }
5146

5147
  *res = buf;
116,569,686✔
5148
  return TSDB_CODE_SUCCESS;
116,578,673✔
5149
}
5150

5151
static int32_t doSaveTupleData(SSerializeDataHandle* pHandle, const void* pBuf, size_t length, SWinKey* key,
182,791,720✔
5152
                               STuplePos* pPos, SFunctionStateStore* pStore) {
5153
  STuplePos p = {0};
182,791,720✔
5154
  if (pHandle->pBuf != NULL) {
182,791,720✔
5155
    SFilePage* pPage = NULL;
182,792,414✔
5156

5157
    if (pHandle->currentPage == -1) {
182,792,414✔
5158
      pPage = getNewBufPage(pHandle->pBuf, &pHandle->currentPage);
5,419,858✔
5159
      if (pPage == NULL) {
5,422,242✔
5160
        return terrno;
×
5161
      }
5162
      pPage->num = sizeof(SFilePage);
5,422,242✔
5163
    } else {
5164
      pPage = getBufPage(pHandle->pBuf, pHandle->currentPage);
177,372,502✔
5165
      if (pPage == NULL) {
177,372,310✔
5166
        return terrno;
×
5167
      }
5168
      if (pPage->num + length > getBufPageSize(pHandle->pBuf)) {
177,372,310✔
5169
        // current page is all used, let's prepare a new buffer page
5170
        releaseBufPage(pHandle->pBuf, pPage);
130,998✔
5171
        pPage = getNewBufPage(pHandle->pBuf, &pHandle->currentPage);
130,998✔
5172
        if (pPage == NULL) {
130,998✔
5173
          return terrno;
×
5174
        }
5175
        pPage->num = sizeof(SFilePage);
130,998✔
5176
      }
5177
    }
5178

5179
    p = (STuplePos){.pageId = pHandle->currentPage, .offset = pPage->num};
182,793,444✔
5180
    (void)memcpy(pPage->data + pPage->num, pBuf, length);
182,795,218✔
5181

5182
    pPage->num += length;
182,794,002✔
5183
    setBufPageDirty(pPage, true);
182,793,618✔
5184
    releaseBufPage(pHandle->pBuf, pPage);
182,793,351✔
5185
  } else {  // other tuple save policy
UNCOV
5186
    if (pStore->streamStateFuncPut(pHandle->pState, key, pBuf, length) >= 0) {
×
5187
      p.streamTupleKey = *key;
×
5188
    }
5189
  }
5190

5191
  *pPos = p;
182,792,096✔
5192
  return TSDB_CODE_SUCCESS;
182,791,436✔
5193
}
5194

5195
int32_t saveTupleData(SqlFunctionCtx* pCtx, int32_t rowIndex, const SSDataBlock* pSrcBlock, STuplePos* pPos) {
77,648,051✔
5196
  int32_t code = prepareBuf(pCtx);
77,648,051✔
5197
  if (TSDB_CODE_SUCCESS != code) {
77,650,152✔
5198
    return code;
×
5199
  }
5200

5201
  SWinKey key = {0};
77,650,152✔
5202
  if (pCtx->saveHandle.pBuf == NULL) {
77,652,098✔
5203
    SColumnInfoData* pColInfo = taosArrayGet(pSrcBlock->pDataBlock, pCtx->saveHandle.pState->tsIndex);
×
5204
    if (NULL == pColInfo) {
×
5205
      return TSDB_CODE_OUT_OF_RANGE;
×
5206
    }
5207
    if (pColInfo->info.type != TSDB_DATA_TYPE_TIMESTAMP) {
×
5208
      return TSDB_CODE_FUNC_FUNTION_PARA_TYPE;
×
5209
    }
5210
    key.groupId = pSrcBlock->info.id.groupId;
×
5211
    key.ts = *(int64_t*)colDataGetData(pColInfo, rowIndex);
×
5212
    key.numInGroup = pCtx->pExpr->pExpr->_function.bindExprID;
×
5213
  }
5214

5215
  char* buf = NULL;
77,652,145✔
5216
  code = serializeTupleData(pCtx, pSrcBlock, rowIndex, &pCtx->subsidiaries, pCtx->subsidiaries.buf, &buf);
77,650,177✔
5217
  if (TSDB_CODE_SUCCESS != code) {
77,649,879✔
5218
    return code;
×
5219
  }
5220
  return doSaveTupleData(&pCtx->saveHandle, buf, pCtx->subsidiaries.rowLen, &key, pPos, pCtx->pStore);
77,649,879✔
5221
}
5222

5223
static int32_t doUpdateTupleData(SSerializeDataHandle* pHandle, const void* pBuf, size_t length, STuplePos* pPos,
38,928,153✔
5224
                                 SFunctionStateStore* pStore) {
5225
  if (pHandle->pBuf != NULL) {
38,928,153✔
5226
    SFilePage* pPage = getBufPage(pHandle->pBuf, pPos->pageId);
38,928,153✔
5227
    if (pPage == NULL) {
38,928,153✔
5228
      return terrno;
×
5229
    }
5230
    (void)memcpy(pPage->data + pPos->offset, pBuf, length);
38,928,153✔
5231
    setBufPageDirty(pPage, true);
38,927,731✔
5232
    releaseBufPage(pHandle->pBuf, pPage);
38,927,309✔
5233
  } else {
5234
    int32_t code = pStore->streamStateFuncPut(pHandle->pState, &pPos->streamTupleKey, pBuf, length);
×
5235
    if (TSDB_CODE_SUCCESS != code) {
×
5236
      return code;
×
5237
    }
5238
  }
5239

5240
  return TSDB_CODE_SUCCESS;
38,926,899✔
5241
}
5242

5243
int32_t updateTupleData(SqlFunctionCtx* pCtx, int32_t rowIndex, const SSDataBlock* pSrcBlock, STuplePos* pPos) {
38,928,153✔
5244
  int32_t code = prepareBuf(pCtx);
38,928,153✔
5245
  if (TSDB_CODE_SUCCESS != code) {
38,927,731✔
5246
    return code;
×
5247
  }
5248

5249
  char* buf = NULL;
38,927,731✔
5250
  code = serializeTupleData(pCtx, pSrcBlock, rowIndex, &pCtx->subsidiaries, pCtx->subsidiaries.buf, &buf);
38,927,731✔
5251
  if (TSDB_CODE_SUCCESS != code) {
38,928,153✔
5252
    return code;
×
5253
  }
5254
  return doUpdateTupleData(&pCtx->saveHandle, buf, pCtx->subsidiaries.rowLen, pPos, pCtx->pStore);
38,928,153✔
5255
}
5256

5257
static int32_t doLoadTupleData(SSerializeDataHandle* pHandle, const STuplePos* pPos, SFunctionStateStore* pStore,
76,606,639✔
5258
                               char** value) {
5259
  if (pHandle->pBuf != NULL) {
76,606,639✔
5260
    SFilePage* pPage = getBufPage(pHandle->pBuf, pPos->pageId);
76,606,639✔
5261
    if (pPage == NULL) {
76,605,558✔
5262
      *value = NULL;
×
5263
      return terrno;
×
5264
    }
5265
    *value = pPage->data + pPos->offset;
76,605,558✔
5266
    releaseBufPage(pHandle->pBuf, pPage);
76,606,639✔
5267
    return TSDB_CODE_SUCCESS;
76,605,141✔
5268
  } else {
UNCOV
5269
    *value = NULL;
×
5270
    int32_t vLen;
×
5271
    int32_t code = pStore->streamStateFuncGet(pHandle->pState, &pPos->streamTupleKey, (void**)(value), &vLen);
×
5272
    if (TSDB_CODE_SUCCESS != code) {
×
5273
      return code;
×
5274
    }
5275
    return TSDB_CODE_SUCCESS;
×
5276
  }
5277
}
5278

5279
int32_t loadTupleData(SqlFunctionCtx* pCtx, const STuplePos* pPos, char** value) {
76,606,639✔
5280
  return doLoadTupleData(&pCtx->saveHandle, pPos, pCtx->pStore, value);
76,606,639✔
5281
}
5282

5283
int32_t topBotFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
7,739,697✔
5284
  int32_t code = TSDB_CODE_SUCCESS;
7,739,697✔
5285

5286
  SResultRowEntryInfo* pEntryInfo = GET_RES_INFO(pCtx);
7,739,697✔
5287
  STopBotRes*          pRes = getTopBotOutputInfo(pCtx);
7,740,319✔
5288

5289
  int16_t type = pCtx->pExpr->base.resSchema.type;
7,740,319✔
5290
  int32_t slotId = pCtx->pExpr->base.resSchema.slotId;
7,740,319✔
5291

5292
  SColumnInfoData* pCol = taosArrayGet(pBlock->pDataBlock, slotId);
7,740,319✔
5293
  if (NULL == pCol) {
7,740,319✔
5294
    return TSDB_CODE_OUT_OF_RANGE;
×
5295
  }
5296

5297
  // todo assign the tag value and the corresponding row data
5298
  int32_t currentRow = pBlock->info.rows;
7,740,319✔
5299
  if (pEntryInfo->numOfRes <= 0) {
7,739,697✔
5300
    colDataSetNULL(pCol, currentRow);
55,836✔
5301
    code = setSelectivityValue(pCtx, pBlock, &pRes->nullTuplePos, currentRow);
55,836✔
5302
    return code;
55,836✔
5303
  }
5304
  for (int32_t i = 0; i < pEntryInfo->numOfRes; ++i) {
52,765,564✔
5305
    STopBotResItem* pItem = &pRes->pItems[i];
45,081,703✔
5306
    code = colDataSetVal(pCol, currentRow, (const char*)&pItem->v.i, false);
45,081,081✔
5307
    if (TSDB_CODE_SUCCESS != code) {
45,081,081✔
5308
      return code;
×
5309
    }
5310
#ifdef BUF_PAGE_DEBUG
5311
    qDebug("page_finalize i:%d,item:%p,pageId:%d, offset:%d\n", i, pItem, pItem->tuplePos.pageId,
5312
           pItem->tuplePos.offset);
5313
#endif
5314
    code = setSelectivityValue(pCtx, pBlock, &pRes->pItems[i].tuplePos, currentRow);
45,081,081✔
5315
    if (TSDB_CODE_SUCCESS != code) {
45,081,703✔
5316
      return code;
×
5317
    }
5318
    currentRow += 1;
45,081,703✔
5319
  }
5320

5321
  return code;
7,684,483✔
5322
}
5323

5324
int32_t addResult(SqlFunctionCtx* pCtx, STopBotResItem* pSourceItem, int16_t type, bool isTopQuery) {
×
5325
  SResultRowEntryInfo* pEntryInfo = GET_RES_INFO(pCtx);
×
5326
  STopBotRes*          pRes = getTopBotOutputInfo(pCtx);
×
5327
  STopBotResItem*      pItems = pRes->pItems;
×
5328
  int32_t              code = TSDB_CODE_SUCCESS;
×
5329

5330
  // not full yet
5331
  if (pEntryInfo->numOfRes < pRes->maxSize) {
×
5332
    STopBotResItem* pItem = &pItems[pEntryInfo->numOfRes];
×
5333
    pItem->v = pSourceItem->v;
×
5334
    pItem->uid = pSourceItem->uid;
×
5335
    pItem->tuplePos.pageId = -1;
×
5336
    replaceTupleData(&pItem->tuplePos, &pSourceItem->tuplePos);
×
5337
    pEntryInfo->numOfRes++;
×
5338
    code = taosheapsort((void*)pItems, sizeof(STopBotResItem), pEntryInfo->numOfRes, (const void*)&type,
×
5339
                        topBotResComparFn, !isTopQuery);
×
5340
    if (TSDB_CODE_SUCCESS != code) {
×
5341
      return code;
×
5342
    }
5343
  } else {  // replace the minimum value in the result
5344
    if ((isTopQuery && ((IS_SIGNED_NUMERIC_TYPE(type) && pSourceItem->v.i > pItems[0].v.i) ||
×
5345
                        (IS_UNSIGNED_NUMERIC_TYPE(type) && pSourceItem->v.u > pItems[0].v.u) ||
×
5346
                        (TSDB_DATA_TYPE_FLOAT == type && pSourceItem->v.f > pItems[0].v.f) ||
×
5347
                        (TSDB_DATA_TYPE_DOUBLE == type && pSourceItem->v.d > pItems[0].v.d))) ||
×
5348
        (!isTopQuery && ((IS_SIGNED_NUMERIC_TYPE(type) && pSourceItem->v.i < pItems[0].v.i) ||
×
5349
                         (IS_UNSIGNED_NUMERIC_TYPE(type) && pSourceItem->v.u < pItems[0].v.u) ||
×
5350
                         (TSDB_DATA_TYPE_FLOAT == type && pSourceItem->v.f < pItems[0].v.f) ||
×
5351
                         (TSDB_DATA_TYPE_DOUBLE == type && pSourceItem->v.d < pItems[0].v.d)))) {
×
5352
      // replace the old data and the coresponding tuple data
5353
      STopBotResItem* pItem = &pItems[0];
×
5354
      pItem->v = pSourceItem->v;
×
5355
      pItem->uid = pSourceItem->uid;
×
5356

5357
      // save the data of this tuple by over writing the old data
5358
      replaceTupleData(&pItem->tuplePos, &pSourceItem->tuplePos);
×
5359
      code = taosheapadjust((void*)pItems, sizeof(STopBotResItem), 0, pEntryInfo->numOfRes - 1, (const void*)&type,
×
5360
                            topBotResComparFn, NULL, !isTopQuery);
×
5361
      if (TSDB_CODE_SUCCESS != code) {
×
5362
        return code;
×
5363
      }
5364
    }
5365
  }
5366
  return code;
×
5367
}
5368

5369
int32_t topCombine(SqlFunctionCtx* pDestCtx, SqlFunctionCtx* pSourceCtx) {
×
5370
  SResultRowEntryInfo* pSResInfo = GET_RES_INFO(pSourceCtx);
×
5371
  STopBotRes*          pSBuf = getTopBotOutputInfo(pSourceCtx);
×
5372
  int16_t              type = pSBuf->type;
×
5373
  int32_t              code = TSDB_CODE_SUCCESS;
×
5374
  for (int32_t i = 0; i < pSResInfo->numOfRes; i++) {
×
5375
    code = addResult(pDestCtx, pSBuf->pItems + i, type, true);
×
5376
    if (TSDB_CODE_SUCCESS != code) {
×
5377
      return code;
×
5378
    }
5379
  }
5380
  return TSDB_CODE_SUCCESS;
×
5381
}
5382

5383
int32_t bottomCombine(SqlFunctionCtx* pDestCtx, SqlFunctionCtx* pSourceCtx) {
×
5384
  SResultRowEntryInfo* pSResInfo = GET_RES_INFO(pSourceCtx);
×
5385
  STopBotRes*          pSBuf = getTopBotOutputInfo(pSourceCtx);
×
5386
  int16_t              type = pSBuf->type;
×
5387
  int32_t              code = TSDB_CODE_SUCCESS;
×
5388
  for (int32_t i = 0; i < pSResInfo->numOfRes; i++) {
×
5389
    code = addResult(pDestCtx, pSBuf->pItems + i, type, false);
×
5390
    if (TSDB_CODE_SUCCESS != code) {
×
5391
      return code;
×
5392
    }
5393
  }
5394
  return TSDB_CODE_SUCCESS;
×
5395
}
5396

5397
int32_t getSpreadInfoSize() { return (int32_t)sizeof(SSpreadInfo); }
8,405,415✔
5398

5399
bool getSpreadFuncEnv(SFunctionNode* UNUSED_PARAM(pFunc), SFuncExecEnv* pEnv) {
3,816,279✔
5400
  pEnv->calcMemSize = sizeof(SSpreadInfo);
3,816,279✔
5401
  return true;
3,815,736✔
5402
}
5403

5404
int32_t spreadFunctionSetup(SqlFunctionCtx* pCtx, SResultRowEntryInfo* pResultInfo) {
83,740,332✔
5405
  if (pResultInfo->initialized) {
83,740,332✔
5406
    return TSDB_CODE_SUCCESS;
×
5407
  }
5408
  if (TSDB_CODE_SUCCESS != functionSetup(pCtx, pResultInfo)) {
83,740,875✔
5409
    return TSDB_CODE_FUNC_SETUP_ERROR;
×
5410
  }
5411

5412
  SSpreadInfo* pInfo = GET_ROWCELL_INTERBUF(pResultInfo);
83,740,954✔
5413
  SET_DOUBLE_VAL(&pInfo->min, DBL_MAX);
83,740,875✔
5414
  SET_DOUBLE_VAL(&pInfo->max, -DBL_MAX);
83,741,497✔
5415
  pInfo->hasResult = false;
83,739,868✔
5416
  return TSDB_CODE_SUCCESS;
83,740,411✔
5417
}
5418

5419
int32_t spreadFunction(SqlFunctionCtx* pCtx) {
133,636,781✔
5420
  int32_t numOfElems = 0;
133,636,781✔
5421

5422
  // Only the pre-computing information loaded and actual data does not loaded
5423
  SInputColumnInfoData* pInput = &pCtx->input;
133,636,781✔
5424
  SColumnDataAgg*       pAgg = pInput->pColumnDataAgg[0];
133,642,476✔
5425
  int32_t               type = pInput->pData[0]->info.type;
133,654,848✔
5426

5427
  SSpreadInfo* pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
133,651,608✔
5428

5429
  if (pInput->colDataSMAIsSet) {
133,648,687✔
5430
    numOfElems = pInput->numOfRows - pAgg->numOfNull;
46,338,491✔
5431
    if (numOfElems == 0) {
46,337,896✔
5432
      goto _spread_over;
32,873,744✔
5433
    }
5434
    double tmin = 0.0, tmax = 0.0;
13,464,152✔
5435
    if (IS_SIGNED_NUMERIC_TYPE(type) || IS_TIMESTAMP_TYPE(type)) {
13,464,152✔
5436
      tmin = (double)GET_INT64_VAL(&pAgg->min);
6,893,366✔
5437
      tmax = (double)GET_INT64_VAL(&pAgg->max);
6,891,500✔
5438
    } else if (IS_FLOAT_TYPE(type)) {
6,570,786✔
UNCOV
5439
      tmin = GET_DOUBLE_VAL(&pAgg->min);
×
5440
      tmax = GET_DOUBLE_VAL(&pAgg->max);
×
5441
    } else if (IS_UNSIGNED_NUMERIC_TYPE(type)) {
6,572,030✔
5442
      tmin = (double)GET_UINT64_VAL(&pAgg->min);
6,571,408✔
5443
      tmax = (double)GET_UINT64_VAL(&pAgg->max);
6,573,274✔
5444
    }
5445

5446
    if (GET_DOUBLE_VAL(&pInfo->min) > tmin) {
13,464,756✔
5447
      SET_DOUBLE_VAL(&pInfo->min, tmin);
612,312✔
5448
    }
5449

5450
    if (GET_DOUBLE_VAL(&pInfo->max) < tmax) {
13,462,881✔
5451
      SET_DOUBLE_VAL(&pInfo->max, tmax);
646,639✔
5452
    }
5453

5454
  } else {  // computing based on the true data block
5455
    SColumnInfoData* pCol = pInput->pData[0];
87,309,340✔
5456

5457
    int32_t start = pInput->startRowIndex;
87,309,859✔
5458
    // check the valid data one by one
5459
    for (int32_t i = start; i < pInput->numOfRows + start; ++i) {
960,653,088✔
5460
      if (colDataIsNull_f(pCol, i)) {
872,747,015✔
5461
        continue;
196,359,212✔
5462
      }
5463

5464
      char* data = colDataGetData(pCol, i);
676,978,030✔
5465

5466
      double v = 0;
676,981,832✔
5467
      GET_TYPED_DATA(v, double, type, data, typeGetTypeModFromColInfo(&pCol->info));
676,981,832✔
5468
      if (v < GET_DOUBLE_VAL(&pInfo->min)) {
676,982,364✔
5469
        SET_DOUBLE_VAL(&pInfo->min, v);
72,919,459✔
5470
      }
5471

5472
      if (v > GET_DOUBLE_VAL(&pInfo->max)) {
676,984,028✔
5473
        SET_DOUBLE_VAL(&pInfo->max, v);
87,859,431✔
5474
      }
5475

5476
      numOfElems += 1;
676,983,461✔
5477
    }
5478
  }
5479

5480
_spread_over:
87,303,581✔
5481
  // data in the check operation are all null, not output
5482
  SET_VAL(GET_RES_INFO(pCtx), numOfElems, 1);
133,643,306✔
5483
  if (numOfElems > 0) {
133,653,188✔
5484
    pInfo->hasResult = true;
91,950,862✔
5485
  }
5486

5487
  return TSDB_CODE_SUCCESS;
133,642,560✔
5488
}
5489

5490
static void spreadTransferInfo(SSpreadInfo* pInput, SSpreadInfo* pOutput) {
7,692,459✔
5491
  pOutput->hasResult = pInput->hasResult;
7,692,459✔
5492
  if (pInput->max > pOutput->max) {
7,692,459✔
5493
    pOutput->max = pInput->max;
5,382,005✔
5494
  }
5495

5496
  if (pInput->min < pOutput->min) {
7,692,459✔
5497
    pOutput->min = pInput->min;
5,379,923✔
5498
  }
5499
}
7,692,459✔
5500

5501
int32_t spreadFunctionMerge(SqlFunctionCtx* pCtx) {
5,702,190✔
5502
  SInputColumnInfoData* pInput = &pCtx->input;
5,702,190✔
5503
  SColumnInfoData*      pCol = pInput->pData[0];
5,702,190✔
5504

5505
  if (IS_NULL_TYPE(pCol->info.type)) {
5,702,190✔
5506
    SET_VAL(GET_RES_INFO(pCtx), 0, 1);
×
5507
    return TSDB_CODE_SUCCESS;
×
5508
  }
5509

5510
  if (pCol->info.type != TSDB_DATA_TYPE_BINARY) {
5,702,190✔
5511
    return TSDB_CODE_FUNC_FUNTION_PARA_TYPE;
×
5512
  }
5513

5514
  SSpreadInfo* pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
5,702,190✔
5515

5516
  int32_t start = pInput->startRowIndex;
5,702,190✔
5517
  for (int32_t i = start; i < start + pInput->numOfRows; ++i) {
13,660,409✔
5518
    if (colDataIsNull_s(pCol, i)) continue;
15,916,438✔
5519
    char*        data = colDataGetData(pCol, i);
7,958,219✔
5520
    SSpreadInfo* pInputInfo = (SSpreadInfo*)varDataVal(data);
7,958,219✔
5521
    if (pInputInfo->hasResult) {
7,958,219✔
5522
      spreadTransferInfo(pInputInfo, pInfo);
7,692,459✔
5523
    }
5524
  }
5525

5526
  if (pInfo->hasResult) {
5,702,190✔
5527
    GET_RES_INFO(pCtx)->numOfRes = 1;
5,562,669✔
5528
  }
5529

5530
  return TSDB_CODE_SUCCESS;
5,702,190✔
5531
}
5532

5533
int32_t spreadFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
67,926,315✔
5534
  SSpreadInfo* pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
67,926,315✔
5535
  if (pInfo->hasResult == true) {
67,925,229✔
5536
    SET_DOUBLE_VAL(&pInfo->result, pInfo->max - pInfo->min);
59,239,748✔
5537
  } else {
5538
    GET_RES_INFO(pCtx)->isNullRes = 1;
8,686,024✔
5539
  }
5540
  return functionFinalize(pCtx, pBlock);
67,926,315✔
5541
}
5542

5543
int32_t spreadPartialFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
7,971,330✔
5544
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
7,971,330✔
5545
  SSpreadInfo*         pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
7,971,961✔
5546
  int32_t              resultBytes = getSpreadInfoSize();
7,971,961✔
5547
  char*                res = taosMemoryCalloc(resultBytes + VARSTR_HEADER_SIZE, sizeof(char));
7,971,330✔
5548

5549
  if (NULL == res) {
7,971,330✔
5550
    return terrno;
×
5551
  }
5552
  (void)memcpy(varDataVal(res), pInfo, resultBytes);
7,971,330✔
5553
  varDataSetLen(res, resultBytes);
7,971,330✔
5554

5555
  int32_t          slotId = pCtx->pExpr->base.resSchema.slotId;
7,971,330✔
5556
  int32_t          code = TSDB_CODE_SUCCESS;
7,971,330✔
5557
  SColumnInfoData* pCol = taosArrayGet(pBlock->pDataBlock, slotId);
7,971,330✔
5558
  if (NULL == pCol) {
7,971,961✔
5559
    code = terrno;
×
5560
    goto _exit;
×
5561
  }
5562

5563
  code = colDataSetVal(pCol, pBlock->info.rows, res, false);
7,971,961✔
5564
  if (TSDB_CODE_SUCCESS != code) {
7,970,776✔
5565
    goto _exit;
×
5566
  }
5567

5568
_exit:
7,970,776✔
5569
  taosMemoryFree(res);
7,970,776✔
5570
  return code;
7,970,776✔
5571
}
5572

5573
int32_t spreadCombine(SqlFunctionCtx* pDestCtx, SqlFunctionCtx* pSourceCtx) {
×
5574
  SResultRowEntryInfo* pDResInfo = GET_RES_INFO(pDestCtx);
×
5575
  SSpreadInfo*         pDBuf = GET_ROWCELL_INTERBUF(pDResInfo);
×
5576

5577
  SResultRowEntryInfo* pSResInfo = GET_RES_INFO(pSourceCtx);
×
5578
  SSpreadInfo*         pSBuf = GET_ROWCELL_INTERBUF(pSResInfo);
×
5579
  spreadTransferInfo(pSBuf, pDBuf);
×
5580
  pDResInfo->numOfRes = TMAX(pDResInfo->numOfRes, pSResInfo->numOfRes);
×
5581
  pDResInfo->isNullRes &= pSResInfo->isNullRes;
×
5582
  return TSDB_CODE_SUCCESS;
×
5583
}
5584

5585
int32_t getElapsedInfoSize() { return (int32_t)sizeof(SElapsedInfo); }
×
5586

5587
bool getElapsedFuncEnv(SFunctionNode* UNUSED_PARAM(pFunc), SFuncExecEnv* pEnv) {
2,456,598✔
5588
  pEnv->calcMemSize = sizeof(SElapsedInfo);
2,456,598✔
5589
  return true;
2,458,182✔
5590
}
5591

5592
int32_t elapsedFunctionSetup(SqlFunctionCtx* pCtx, SResultRowEntryInfo* pResultInfo) {
4,712,126✔
5593
  if (pResultInfo->initialized) {
4,712,126✔
5594
    return TSDB_CODE_SUCCESS;
×
5595
  }
5596
  if (TSDB_CODE_SUCCESS != functionSetup(pCtx, pResultInfo)) {
4,712,126✔
5597
    return TSDB_CODE_FUNC_SETUP_ERROR;
×
5598
  }
5599

5600
  SElapsedInfo* pInfo = GET_ROWCELL_INTERBUF(pResultInfo);
4,711,583✔
5601
  pInfo->result = 0;
4,711,583✔
5602
  pInfo->min = TSKEY_MAX;
4,712,126✔
5603
  pInfo->max = 0;
4,712,126✔
5604

5605
  if (pCtx->numOfParams > 1) {
4,712,126✔
5606
    pInfo->timeUnit = pCtx->param[1].param.i;
3,084,788✔
5607
  } else {
5608
    pInfo->timeUnit = 1;
1,626,795✔
5609
  }
5610

5611
  return TSDB_CODE_SUCCESS;
4,711,664✔
5612
}
5613

5614
int32_t elapsedFunction(SqlFunctionCtx* pCtx) {
4,772,332✔
5615
  int32_t numOfElems = 0;
4,772,332✔
5616

5617
  // Only the pre-computing information loaded and actual data does not loaded
5618
  SInputColumnInfoData* pInput = &pCtx->input;
4,772,332✔
5619
  SColumnDataAgg*       pAgg = pInput->pColumnDataAgg[0];
4,772,332✔
5620

5621
  SElapsedInfo* pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
4,772,332✔
5622

5623
  numOfElems = pInput->numOfRows;  // since this is the primary timestamp, no need to exclude NULL values
4,772,332✔
5624
  if (numOfElems == 0) {
4,771,870✔
5625
    // for stream
5626
    if (pCtx->end.key != INT64_MIN) {
×
5627
      pInfo->max = pCtx->end.key + 1;
×
5628
    }
5629
    goto _elapsed_over;
×
5630
  }
5631

5632
  if (pInput->colDataSMAIsSet) {
4,771,870✔
5633
    if (pInfo->min == TSKEY_MAX) {
×
5634
      pInfo->min = GET_INT64_VAL(&pAgg->min);
×
5635
      pInfo->max = GET_INT64_VAL(&pAgg->max);
×
5636
    } else {
5637
      if (pCtx->order == TSDB_ORDER_ASC) {
×
5638
        pInfo->max = GET_INT64_VAL(&pAgg->max);
×
5639
      } else {
5640
        pInfo->min = GET_INT64_VAL(&pAgg->min);
×
5641
      }
5642
    }
5643
  } else {  // computing based on the true data block
5644
    if (0 == pInput->numOfRows) {
4,771,789✔
5645
      if (pCtx->order == TSDB_ORDER_DESC) {
×
5646
        if (pCtx->end.key != INT64_MIN) {
×
5647
          pInfo->min = pCtx->end.key;
×
5648
        }
5649
      } else {
5650
        if (pCtx->end.key != INT64_MIN) {
×
5651
          pInfo->max = pCtx->end.key + 1;
×
5652
        }
5653
      }
5654
      goto _elapsed_over;
×
5655
    }
5656

5657
    SColumnInfoData* pCol = pInput->pData[0];
4,771,246✔
5658

5659
    int32_t start = pInput->startRowIndex;
4,771,327✔
5660
    TSKEY*  ptsList = (int64_t*)colDataGetData(pCol, 0);
4,772,332✔
5661
    if (pCtx->order == TSDB_ORDER_DESC) {
4,771,789✔
5662
      if (pCtx->start.key == INT64_MIN) {
34,408✔
5663
        pInfo->max = (pInfo->max < ptsList[start]) ? ptsList[start] : pInfo->max;
34,408✔
5664
      } else {
5665
        pInfo->max = pCtx->start.key + 1;
×
5666
      }
5667

5668
      if (pCtx->end.key == INT64_MIN) {
34,408✔
5669
        pInfo->min =
34,408✔
5670
            (pInfo->min > ptsList[start + pInput->numOfRows - 1]) ? ptsList[start + pInput->numOfRows - 1] : pInfo->min;
34,408✔
5671
      } else {
5672
        pInfo->min = pCtx->end.key;
×
5673
      }
5674
    } else {
5675
      if (pCtx->start.key == INT64_MIN) {
4,736,376✔
5676
        pInfo->min = (pInfo->min > ptsList[start]) ? ptsList[start] : pInfo->min;
4,737,462✔
5677
      } else {
5678
        pInfo->min = pCtx->start.key;
×
5679
      }
5680

5681
      if (pCtx->end.key == INT64_MIN) {
4,737,924✔
5682
        pInfo->max =
4,676,811✔
5683
            (pInfo->max < ptsList[start + pInput->numOfRows - 1]) ? ptsList[start + pInput->numOfRows - 1] : pInfo->max;
4,677,273✔
5684
      } else {
5685
        pInfo->max = pCtx->end.key + 1;
60,651✔
5686
      }
5687
    }
5688
  }
5689

5690
_elapsed_over:
4,771,789✔
5691
  // data in the check operation are all null, not output
5692
  SET_VAL(GET_RES_INFO(pCtx), numOfElems, 1);
4,771,789✔
5693

5694
  return TSDB_CODE_SUCCESS;
4,771,789✔
5695
}
5696

5697
static void elapsedTransferInfo(SElapsedInfo* pInput, SElapsedInfo* pOutput) {
×
5698
  pOutput->timeUnit = pInput->timeUnit;
×
5699
  if (pOutput->min > pInput->min) {
×
5700
    pOutput->min = pInput->min;
×
5701
  }
5702

5703
  if (pOutput->max < pInput->max) {
×
5704
    pOutput->max = pInput->max;
×
5705
  }
5706
}
×
5707

5708
int32_t elapsedFunctionMerge(SqlFunctionCtx* pCtx) {
×
5709
  SInputColumnInfoData* pInput = &pCtx->input;
×
5710
  SColumnInfoData*      pCol = pInput->pData[0];
×
5711
  if (pCol->info.type != TSDB_DATA_TYPE_BINARY) {
×
5712
    return TSDB_CODE_FUNC_FUNTION_PARA_TYPE;
×
5713
  }
5714

5715
  SElapsedInfo* pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
×
5716

5717
  int32_t start = pInput->startRowIndex;
×
5718

5719
  for (int32_t i = start; i < start + pInput->numOfRows; ++i) {
×
5720
    char*         data = colDataGetData(pCol, i);
×
5721
    SElapsedInfo* pInputInfo = (SElapsedInfo*)varDataVal(data);
×
5722
    elapsedTransferInfo(pInputInfo, pInfo);
×
5723
  }
5724

5725
  SET_VAL(GET_RES_INFO(pCtx), 1, 1);
×
5726
  return TSDB_CODE_SUCCESS;
×
5727
}
5728

5729
int32_t elapsedFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
4,712,126✔
5730
  SElapsedInfo* pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
4,712,126✔
5731
  double        result = (double)(pInfo->max - pInfo->min);
4,712,126✔
5732
  pInfo->result = fabs(result) / pInfo->timeUnit;
4,712,126✔
5733
  return functionFinalize(pCtx, pBlock);
4,712,126✔
5734
}
5735

5736
int32_t elapsedPartialFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
×
5737
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
×
5738
  SElapsedInfo*        pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
×
5739
  int32_t              resultBytes = getElapsedInfoSize();
×
5740
  char*                res = taosMemoryCalloc(resultBytes + VARSTR_HEADER_SIZE, sizeof(char));
×
5741

5742
  if (NULL == res) {
×
5743
    return terrno;
×
5744
  }
5745
  (void)memcpy(varDataVal(res), pInfo, resultBytes);
×
5746
  varDataSetLen(res, resultBytes);
×
5747

5748
  int32_t          slotId = pCtx->pExpr->base.resSchema.slotId;
×
5749
  int32_t          code = TSDB_CODE_SUCCESS;
×
5750
  SColumnInfoData* pCol = taosArrayGet(pBlock->pDataBlock, slotId);
×
5751
  if (NULL == pCol) {
×
5752
    code = terrno;
×
5753
    goto _exit;
×
5754
  }
5755

5756
  code = colDataSetVal(pCol, pBlock->info.rows, res, false);
×
5757
  if (TSDB_CODE_SUCCESS != code) {
×
5758
    goto _exit;
×
5759
  }
5760
_exit:
×
5761
  taosMemoryFree(res);
×
5762
  return code;
×
5763
}
5764

5765
int32_t elapsedCombine(SqlFunctionCtx* pDestCtx, SqlFunctionCtx* pSourceCtx) {
×
5766
  SResultRowEntryInfo* pDResInfo = GET_RES_INFO(pDestCtx);
×
5767
  SElapsedInfo*        pDBuf = GET_ROWCELL_INTERBUF(pDResInfo);
×
5768

5769
  SResultRowEntryInfo* pSResInfo = GET_RES_INFO(pSourceCtx);
×
5770
  SElapsedInfo*        pSBuf = GET_ROWCELL_INTERBUF(pSResInfo);
×
5771

5772
  elapsedTransferInfo(pSBuf, pDBuf);
×
5773
  pDResInfo->numOfRes = TMAX(pDResInfo->numOfRes, pSResInfo->numOfRes);
×
5774
  pDResInfo->isNullRes &= pSResInfo->isNullRes;
×
5775
  return TSDB_CODE_SUCCESS;
×
5776
}
5777

5778
int32_t getHistogramInfoSize() {
755,095✔
5779
  return (int32_t)sizeof(SHistoFuncInfo) + HISTOGRAM_MAX_BINS_NUM * sizeof(SHistoFuncBin);
755,095✔
5780
}
5781

5782
bool getHistogramFuncEnv(SFunctionNode* UNUSED_PARAM(pFunc), SFuncExecEnv* pEnv) {
1,360,895✔
5783
  pEnv->calcMemSize = sizeof(SHistoFuncInfo) + HISTOGRAM_MAX_BINS_NUM * sizeof(SHistoFuncBin);
1,360,895✔
5784
  return true;
1,361,652✔
5785
}
5786

5787
static int8_t getHistogramBinType(char* binTypeStr) {
937,679✔
5788
  int8_t binType;
5789
  if (strcasecmp(binTypeStr, "user_input") == 0) {
937,679✔
5790
    binType = USER_INPUT_BIN;
166,742✔
5791
  } else if (strcasecmp(binTypeStr, "linear_bin") == 0) {
770,937✔
5792
    binType = LINEAR_BIN;
379,749✔
5793
  } else if (strcasecmp(binTypeStr, "log_bin") == 0) {
391,188✔
5794
    binType = LOG_BIN;
390,645✔
5795
  } else {
5796
    binType = UNKNOWN_BIN;
543✔
5797
  }
5798

5799
  return binType;
937,679✔
5800
}
5801

5802
static int32_t getHistogramBinDesc(SHistoFuncInfo* pInfo, char* binDescStr, int8_t binType, bool normalized) {
937,679✔
5803
  cJSON*  binDesc = cJSON_Parse(binDescStr);
937,679✔
5804
  int32_t numOfBins;
5805
  double* intervals;
5806
  if (cJSON_IsObject(binDesc)) { /* linaer/log bins */
937,679✔
5807
    int32_t numOfParams = cJSON_GetArraySize(binDesc);
770,937✔
5808
    int32_t startIndex;
5809
    if (numOfParams != 4) {
770,555✔
5810
      cJSON_Delete(binDesc);
×
5811
      return TSDB_CODE_FAILED;
×
5812
    }
5813

5814
    cJSON* start = cJSON_GetObjectItem(binDesc, "start");
770,555✔
5815
    cJSON* factor = cJSON_GetObjectItem(binDesc, "factor");
769,630✔
5816
    cJSON* width = cJSON_GetObjectItem(binDesc, "width");
770,937✔
5817
    cJSON* count = cJSON_GetObjectItem(binDesc, "count");
770,555✔
5818
    cJSON* infinity = cJSON_GetObjectItem(binDesc, "infinity");
770,937✔
5819

5820
    if (!cJSON_IsNumber(start) || !cJSON_IsNumber(count) || !cJSON_IsBool(infinity)) {
770,173✔
5821
      cJSON_Delete(binDesc);
161✔
5822
      return TSDB_CODE_FAILED;
×
5823
    }
5824

5825
    if (count->valueint <= 0 || count->valueint > 1000) {  // limit count to 1000
770,937✔
5826
      cJSON_Delete(binDesc);
161✔
5827
      return TSDB_CODE_FAILED;
×
5828
    }
5829

5830
    if (isinf(start->valuedouble) || (width != NULL && isinf(width->valuedouble)) ||
770,937✔
5831
        (factor != NULL && isinf(factor->valuedouble)) || (count != NULL && isinf(count->valuedouble))) {
770,012✔
5832
      cJSON_Delete(binDesc);
×
5833
      return TSDB_CODE_FAILED;
×
5834
    }
5835

5836
    int32_t counter = (int32_t)count->valueint;
770,937✔
5837
    if (infinity->valueint == false) {
770,555✔
5838
      startIndex = 0;
712,947✔
5839
      numOfBins = counter + 1;
712,947✔
5840
    } else {
5841
      startIndex = 1;
57,065✔
5842
      numOfBins = counter + 3;
57,065✔
5843
    }
5844

5845
    intervals = taosMemoryCalloc(numOfBins, sizeof(double));
770,012✔
5846
    if (NULL == intervals) {
770,173✔
5847
      cJSON_Delete(binDesc);
×
5848
      qError("histogram function out of memory");
×
5849
      return terrno;
×
5850
    }
5851
    if (cJSON_IsNumber(width) && factor == NULL && binType == LINEAR_BIN) {
770,173✔
5852
      // linear bin process
5853
      if (width->valuedouble == 0) {
380,292✔
5854
        taosMemoryFree(intervals);
×
5855
        cJSON_Delete(binDesc);
×
5856
        return TSDB_CODE_FAILED;
×
5857
      }
5858
      for (int i = 0; i < counter + 1; ++i) {
2,349,276✔
5859
        intervals[startIndex] = start->valuedouble + i * width->valuedouble;
1,968,441✔
5860
        if (isinf(intervals[startIndex])) {
1,967,898✔
5861
          taosMemoryFree(intervals);
×
5862
          cJSON_Delete(binDesc);
×
5863
          return TSDB_CODE_FAILED;
×
5864
        }
5865
        startIndex++;
1,968,984✔
5866
      }
5867
    } else if (cJSON_IsNumber(factor) && width == NULL && binType == LOG_BIN) {
390,645✔
5868
      // log bin process
5869
      if (start->valuedouble == 0) {
390,645✔
5870
        taosMemoryFree(intervals);
×
5871
        cJSON_Delete(binDesc);
×
5872
        return TSDB_CODE_FAILED;
×
5873
      }
5874
      if (factor->valuedouble < 0 || factor->valuedouble == 0 || factor->valuedouble == 1) {
390,645✔
5875
        taosMemoryFree(intervals);
×
5876
        cJSON_Delete(binDesc);
×
5877
        return TSDB_CODE_FAILED;
×
5878
      }
5879
      for (int i = 0; i < counter + 1; ++i) {
2,419,073✔
5880
        intervals[startIndex] = start->valuedouble * pow(factor->valuedouble, i * 1.0);
2,027,541✔
5881
        if (isinf(intervals[startIndex])) {
2,027,159✔
5882
          taosMemoryFree(intervals);
×
5883
          cJSON_Delete(binDesc);
×
5884
          return TSDB_CODE_FAILED;
×
5885
        }
5886
        startIndex++;
2,028,428✔
5887
      }
5888
    } else {
5889
      taosMemoryFree(intervals);
×
5890
      cJSON_Delete(binDesc);
×
5891
      return TSDB_CODE_FAILED;
×
5892
    }
5893

5894
    if (infinity->valueint == true) {
772,367✔
5895
      intervals[0] = -INFINITY;
57,065✔
5896
      intervals[numOfBins - 1] = INFINITY;
57,065✔
5897
      // in case of desc bin orders, -inf/inf should be swapped
5898
      if (numOfBins < 4) {
57,065✔
5899
        return TSDB_CODE_FAILED;
×
5900
      }
5901
      if (intervals[1] > intervals[numOfBins - 2]) {
57,065✔
5902
        TSWAP(intervals[0], intervals[numOfBins - 1]);
57,065✔
5903
      }
5904
    }
5905
  } else if (cJSON_IsArray(binDesc)) { /* user input bins */
166,742✔
5906
    if (binType != USER_INPUT_BIN) {
166,742✔
5907
      cJSON_Delete(binDesc);
×
5908
      return TSDB_CODE_FAILED;
×
5909
    }
5910
    numOfBins = cJSON_GetArraySize(binDesc);
166,742✔
5911
    intervals = taosMemoryCalloc(numOfBins, sizeof(double));
166,742✔
5912
    if (NULL == intervals) {
166,742✔
5913
      cJSON_Delete(binDesc);
×
5914
      qError("histogram function out of memory");
×
5915
      return terrno;
×
5916
    }
5917
    cJSON* bin = binDesc->child;
166,742✔
5918
    if (bin == NULL) {
166,742✔
5919
      taosMemoryFree(intervals);
×
5920
      cJSON_Delete(binDesc);
×
5921
      return TSDB_CODE_FAILED;
×
5922
    }
5923
    int i = 0;
166,742✔
5924
    while (bin) {
520,318✔
5925
      intervals[i] = bin->valuedouble;
353,576✔
5926
      if (!cJSON_IsNumber(bin)) {
353,576✔
5927
        taosMemoryFree(intervals);
×
5928
        cJSON_Delete(binDesc);
×
5929
        return TSDB_CODE_FAILED;
×
5930
      }
5931
      if (i != 0 && intervals[i] <= intervals[i - 1]) {
353,576✔
5932
        taosMemoryFree(intervals);
×
5933
        cJSON_Delete(binDesc);
×
5934
        return TSDB_CODE_FAILED;
×
5935
      }
5936
      bin = bin->next;
353,576✔
5937
      i++;
353,576✔
5938
    }
5939
  } else {
5940
    cJSON_Delete(binDesc);
×
5941
    return TSDB_CODE_FAILED;
×
5942
  }
5943

5944
  pInfo->numOfBins = numOfBins - 1;
937,679✔
5945
  pInfo->normalized = normalized;
937,679✔
5946
  for (int32_t i = 0; i < pInfo->numOfBins; ++i) {
4,463,085✔
5947
    pInfo->bins[i].lower = intervals[i] < intervals[i + 1] ? intervals[i] : intervals[i + 1];
3,527,316✔
5948
    pInfo->bins[i].upper = intervals[i + 1] > intervals[i] ? intervals[i + 1] : intervals[i];
3,525,886✔
5949
    pInfo->bins[i].count = 0;
3,527,316✔
5950
  }
5951

5952
  taosMemoryFree(intervals);
936,028✔
5953
  cJSON_Delete(binDesc);
936,915✔
5954

5955
  return TSDB_CODE_SUCCESS;
937,679✔
5956
}
5957

5958
int32_t histogramFunctionSetup(SqlFunctionCtx* pCtx, SResultRowEntryInfo* pResultInfo) {
937,679✔
5959
  if (pResultInfo->initialized) {
937,679✔
5960
    return TSDB_CODE_SUCCESS;
×
5961
  }
5962
  if (TSDB_CODE_SUCCESS != functionSetup(pCtx, pResultInfo)) {
937,679✔
5963
    return TSDB_CODE_FUNC_SETUP_ERROR;
×
5964
  }
5965

5966
  SHistoFuncInfo* pInfo = GET_ROWCELL_INTERBUF(pResultInfo);
937,679✔
5967
  pInfo->numOfBins = 0;
937,679✔
5968
  pInfo->totalCount = 0;
937,679✔
5969
  pInfo->normalized = 0;
937,679✔
5970

5971
  char* binTypeStr = taosStrndup(varDataVal(pCtx->param[1].param.pz), varDataLen(pCtx->param[1].param.pz));
937,679✔
5972
  if (binTypeStr == NULL) {
937,679✔
5973
    return terrno;
×
5974
  }
5975
  int8_t binType = getHistogramBinType(binTypeStr);
937,679✔
5976
  taosMemoryFree(binTypeStr);
937,136✔
5977

5978
  if (binType == UNKNOWN_BIN) {
937,679✔
5979
    return TSDB_CODE_FUNC_FUNTION_PARA_VALUE;
×
5980
  }
5981
  char* binDesc = taosStrndup(varDataVal(pCtx->param[2].param.pz), varDataLen(pCtx->param[2].param.pz));
937,679✔
5982
  if (binDesc == NULL) {
937,679✔
5983
    return terrno;
×
5984
  }
5985
  int64_t normalized = pCtx->param[3].param.i;
937,679✔
5986
  if (normalized != 0 && normalized != 1) {
937,679✔
5987
    taosMemoryFree(binDesc);
×
5988
    return TSDB_CODE_FUNC_FUNTION_PARA_VALUE;
×
5989
  }
5990
  int32_t code = getHistogramBinDesc(pInfo, binDesc, binType, (bool)normalized);
937,679✔
5991
  if (TSDB_CODE_SUCCESS != code) {
937,679✔
5992
    taosMemoryFree(binDesc);
×
5993
    return code;
×
5994
  }
5995
  taosMemoryFree(binDesc);
937,679✔
5996

5997
  return TSDB_CODE_SUCCESS;
937,297✔
5998
}
5999

6000
static int32_t histogramFunctionImpl(SqlFunctionCtx* pCtx, bool isPartial) {
1,092,354✔
6001
  SHistoFuncInfo* pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
1,092,354✔
6002

6003
  SInputColumnInfoData* pInput = &pCtx->input;
1,091,972✔
6004
  SColumnInfoData*      pCol = pInput->pData[0];
1,092,897✔
6005

6006
  int32_t type = pInput->pData[0]->info.type;
1,092,133✔
6007

6008
  int32_t start = pInput->startRowIndex;
1,092,897✔
6009
  int32_t numOfRows = pInput->numOfRows;
1,092,897✔
6010

6011
  int32_t numOfElems = 0;
1,094,036✔
6012
  for (int32_t i = start; i < numOfRows + start; ++i) {
157,952,976✔
6013
    if (pCol->hasNull && colDataIsNull_f(pCol, i)) {
156,860,079✔
6014
      continue;
46,458,466✔
6015
    }
6016

6017
    numOfElems++;
110,400,481✔
6018

6019
    char*  data = colDataGetData(pCol, i);
110,400,481✔
6020
    double v;
6021
    GET_TYPED_DATA(v, double, type, data, typeGetTypeModFromColInfo(&pCol->info));
110,410,511✔
6022

6023
    for (int32_t k = 0; k < pInfo->numOfBins; ++k) {
517,414,276✔
6024
      if (v > pInfo->bins[k].lower && v <= pInfo->bins[k].upper) {
427,317,273✔
6025
        pInfo->bins[k].count++;
20,360,108✔
6026
        pInfo->totalCount++;
20,360,108✔
6027
        break;
20,360,108✔
6028
      }
6029
    }
6030
  }
6031

6032
  if (!isPartial) {
1,092,897✔
6033
    GET_RES_INFO(pCtx)->numOfRes = pInfo->numOfBins;
740,597✔
6034
  } else {
6035
    GET_RES_INFO(pCtx)->numOfRes = 1;
352,300✔
6036
  }
6037
  return TSDB_CODE_SUCCESS;
1,092,897✔
6038
}
6039

6040
int32_t histogramFunction(SqlFunctionCtx* pCtx) { return histogramFunctionImpl(pCtx, false); }
740,054✔
6041

6042
int32_t histogramFunctionPartial(SqlFunctionCtx* pCtx) { return histogramFunctionImpl(pCtx, true); }
352,300✔
6043

6044
static void histogramTransferInfo(SHistoFuncInfo* pInput, SHistoFuncInfo* pOutput) {
225,220✔
6045
  pOutput->normalized = pInput->normalized;
225,220✔
6046
  pOutput->numOfBins = pInput->numOfBins;
225,220✔
6047
  pOutput->totalCount += pInput->totalCount;
225,220✔
6048
  for (int32_t k = 0; k < pOutput->numOfBins; ++k) {
1,391,568✔
6049
    pOutput->bins[k].lower = pInput->bins[k].lower;
1,166,348✔
6050
    pOutput->bins[k].upper = pInput->bins[k].upper;
1,166,348✔
6051
    pOutput->bins[k].count += pInput->bins[k].count;
1,166,348✔
6052
  }
6053
}
225,220✔
6054

6055
int32_t histogramFunctionMerge(SqlFunctionCtx* pCtx) {
225,220✔
6056
  SInputColumnInfoData* pInput = &pCtx->input;
225,220✔
6057
  SColumnInfoData*      pCol = pInput->pData[0];
225,220✔
6058
  if (pCol->info.type != TSDB_DATA_TYPE_BINARY) {
225,220✔
6059
    return TSDB_CODE_FUNC_FUNTION_PARA_TYPE;
×
6060
  }
6061

6062
  SHistoFuncInfo* pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
225,220✔
6063

6064
  int32_t start = pInput->startRowIndex;
225,220✔
6065

6066
  for (int32_t i = start; i < start + pInput->numOfRows; ++i) {
450,440✔
6067
    char*           data = colDataGetData(pCol, i);
225,220✔
6068
    SHistoFuncInfo* pInputInfo = (SHistoFuncInfo*)varDataVal(data);
225,220✔
6069
    histogramTransferInfo(pInputInfo, pInfo);
225,220✔
6070
  }
6071

6072
  SET_VAL(GET_RES_INFO(pCtx), pInfo->numOfBins, pInfo->numOfBins);
225,220✔
6073
  return TSDB_CODE_SUCCESS;
225,220✔
6074
}
6075

6076
int32_t histogramFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
915,418✔
6077
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
915,418✔
6078
  SHistoFuncInfo*      pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
915,418✔
6079
  int32_t              slotId = pCtx->pExpr->base.resSchema.slotId;
915,418✔
6080
  SColumnInfoData*     pCol = taosArrayGet(pBlock->pDataBlock, slotId);
915,418✔
6081
  int32_t              code = TSDB_CODE_SUCCESS;
915,418✔
6082

6083
  int32_t currentRow = pBlock->info.rows;
915,418✔
6084
  if (NULL == pCol) {
915,036✔
6085
    return TSDB_CODE_OUT_OF_RANGE;
×
6086
  }
6087

6088
  if (pInfo->normalized) {
915,036✔
6089
    for (int32_t k = 0; k < pResInfo->numOfRes; ++k) {
2,320,688✔
6090
      if (pInfo->totalCount != 0) {
1,774,278✔
6091
        pInfo->bins[k].percentage = pInfo->bins[k].count / (double)pInfo->totalCount;
48,750✔
6092
      } else {
6093
        pInfo->bins[k].percentage = 0;
1,725,528✔
6094
      }
6095
    }
6096
  }
6097

6098
  for (int32_t i = 0; i < pResInfo->numOfRes; ++i) {
4,310,005✔
6099
    int32_t len;
6100
    char    buf[512] = {0};
3,394,050✔
6101
    if (!pInfo->normalized) {
3,394,580✔
6102
      len = snprintf(varDataVal(buf), sizeof(buf) - VARSTR_HEADER_SIZE,
1,620,684✔
6103
                     "{\"lower_bin\":%g, \"upper_bin\":%g, \"count\":%" PRId64 "}", pInfo->bins[i].lower,
6104
                     pInfo->bins[i].upper, pInfo->bins[i].count);
6105
    } else {
6106
      len = snprintf(varDataVal(buf), sizeof(buf) - VARSTR_HEADER_SIZE,
1,774,278✔
6107
                     "{\"lower_bin\":%g, \"upper_bin\":%g, \"count\":%lf}", pInfo->bins[i].lower, pInfo->bins[i].upper,
6108
                     pInfo->bins[i].percentage);
6109
    }
6110
    varDataSetLen(buf, len);
3,394,962✔
6111
    code = colDataSetVal(pCol, currentRow, buf, false);
3,394,962✔
6112
    if (TSDB_CODE_SUCCESS != code) {
3,394,587✔
6113
      return code;
×
6114
    }
6115
    currentRow++;
3,394,587✔
6116
  }
6117

6118
  return code;
915,418✔
6119
}
6120

6121
int32_t histogramPartialFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
225,220✔
6122
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
225,220✔
6123
  SHistoFuncInfo*      pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
225,220✔
6124
  int32_t              resultBytes = getHistogramInfoSize();
225,220✔
6125
  char*                res = taosMemoryCalloc(resultBytes + VARSTR_HEADER_SIZE, sizeof(char));
225,220✔
6126

6127
  if (NULL == res) {
225,220✔
6128
    return terrno;
×
6129
  }
6130
  (void)memcpy(varDataVal(res), pInfo, resultBytes);
225,220✔
6131
  varDataSetLen(res, resultBytes);
225,220✔
6132

6133
  int32_t          slotId = pCtx->pExpr->base.resSchema.slotId;
225,220✔
6134
  int32_t          code = TSDB_CODE_SUCCESS;
225,220✔
6135
  SColumnInfoData* pCol = taosArrayGet(pBlock->pDataBlock, slotId);
225,220✔
6136
  if (NULL == pCol) {
225,220✔
6137
    code = terrno;
×
6138
    goto _exit;
×
6139
  }
6140
  code = colDataSetVal(pCol, pBlock->info.rows, res, false);
225,220✔
6141

6142
_exit:
225,220✔
6143
  taosMemoryFree(res);
225,220✔
6144
  return code;
225,220✔
6145
}
6146

6147
int32_t histogramCombine(SqlFunctionCtx* pDestCtx, SqlFunctionCtx* pSourceCtx) {
×
6148
  SResultRowEntryInfo* pDResInfo = GET_RES_INFO(pDestCtx);
×
6149
  SHistoFuncInfo*      pDBuf = GET_ROWCELL_INTERBUF(pDResInfo);
×
6150

6151
  SResultRowEntryInfo* pSResInfo = GET_RES_INFO(pSourceCtx);
×
6152
  SHistoFuncInfo*      pSBuf = GET_ROWCELL_INTERBUF(pSResInfo);
×
6153

6154
  histogramTransferInfo(pSBuf, pDBuf);
×
6155
  pDResInfo->numOfRes = TMAX(pDResInfo->numOfRes, pSResInfo->numOfRes);
×
6156
  pDResInfo->isNullRes &= pSResInfo->isNullRes;
×
6157
  return TSDB_CODE_SUCCESS;
×
6158
}
6159

6160
int32_t getHLLInfoSize() { return (int32_t)sizeof(SHLLInfo); }
264,221✔
6161

6162
bool getHLLFuncEnv(SFunctionNode* UNUSED_PARAM(pFunc), SFuncExecEnv* pEnv) {
3,879,806✔
6163
  pEnv->calcMemSize = sizeof(SHLLInfo);
3,879,806✔
6164
  return true;
3,880,892✔
6165
}
6166

6167
static uint8_t hllCountNum(void* data, int32_t bytes, int32_t* buk) {
586,923,653✔
6168
  uint64_t hash = MurmurHash3_64(data, bytes);
586,923,653✔
6169
  int32_t  index = hash & HLL_BUCKET_MASK;
586,904,105✔
6170
  hash >>= HLL_BUCKET_BITS;
586,904,105✔
6171
  hash |= ((uint64_t)1 << HLL_DATA_BITS);
586,904,105✔
6172
  uint64_t bit = 1;
586,904,105✔
6173
  uint8_t  count = 1;
586,904,105✔
6174
  while ((hash & bit) == 0) {
867,470,903✔
6175
    count++;
280,566,798✔
6176
    bit <<= 1;
280,566,798✔
6177
  }
6178
  *buk = index;
586,904,105✔
6179
  return count;
586,909,535✔
6180
}
6181

6182
static void hllBucketHisto(uint8_t* buckets, int32_t* bucketHisto) {
9,260,800✔
6183
  uint64_t* word = (uint64_t*)buckets;
9,260,800✔
6184
  uint8_t*  bytes;
6185

6186
  for (int32_t j = 0; j < HLL_BUCKETS >> 3; j++) {
2,147,483,647✔
6187
    if (*word == 0) {
2,147,483,647✔
6188
      bucketHisto[0] += 8;
2,147,483,647✔
6189
    } else {
6190
      bytes = (uint8_t*)word;
28,894,258✔
6191
      bucketHisto[bytes[0]]++;
28,894,258✔
6192
      bucketHisto[bytes[1]]++;
31,963,102✔
6193
      bucketHisto[bytes[2]]++;
31,963,102✔
6194
      bucketHisto[bytes[3]]++;
31,963,102✔
6195
      bucketHisto[bytes[4]]++;
31,963,102✔
6196
      bucketHisto[bytes[5]]++;
31,963,102✔
6197
      bucketHisto[bytes[6]]++;
31,963,102✔
6198
      bucketHisto[bytes[7]]++;
31,963,102✔
6199
    }
6200
    word++;
2,147,483,647✔
6201
  }
6202
}
3,695,338✔
6203
static double hllTau(double x) {
9,260,800✔
6204
  if (x == 0. || x == 1.) return 0.;
9,260,800✔
6205
  double zPrime;
6206
  double y = 1.0;
×
6207
  double z = 1 - x;
×
6208
  do {
6209
    x = sqrt(x);
×
6210
    zPrime = z;
×
6211
    y *= 0.5;
×
6212
    z -= pow(1 - x, 2) * y;
×
6213
  } while (zPrime != z);
×
6214
  return z / 3;
×
6215
}
6216

6217
static double hllSigma(double x) {
9,260,800✔
6218
  if (x == 1.0) return INFINITY;
9,260,800✔
6219
  double zPrime;
6220
  double y = 1;
8,441,589✔
6221
  double z = x;
8,441,589✔
6222
  do {
6223
    x *= x;
167,543,807✔
6224
    zPrime = z;
167,543,807✔
6225
    z += x * y;
167,543,807✔
6226
    y += y;
167,543,807✔
6227
  } while (zPrime != z);
167,543,807✔
6228
  return z;
8,441,589✔
6229
}
6230

6231
// estimate the cardinality, the algorithm refer this paper: "New cardinality estimation algorithms for HyperLogLog
6232
// sketches"
6233
static uint64_t hllCountCnt(uint8_t* buckets) {
9,260,800✔
6234
  double  m = HLL_BUCKETS;
9,260,800✔
6235
  int32_t buckethisto[64] = {0};
9,260,800✔
6236
  hllBucketHisto(buckets, buckethisto);
9,260,800✔
6237

6238
  double z = m * hllTau((m - buckethisto[HLL_DATA_BITS + 1]) / (double)m);
9,260,800✔
6239
  for (int j = HLL_DATA_BITS; j >= 1; --j) {
472,252,473✔
6240
    z += buckethisto[j];
462,991,673✔
6241
    z *= 0.5;
462,991,673✔
6242
  }
6243

6244
  z += m * hllSigma(buckethisto[0] / (double)m);
9,260,800✔
6245
  double E = (double)llroundl(HLL_ALPHA_INF * m * m / z);
9,260,800✔
6246

6247
  return (uint64_t)E;
9,260,800✔
6248
}
6249

6250
int32_t hllFunction(SqlFunctionCtx* pCtx) {
9,516,308✔
6251
  SHLLInfo* pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
9,516,308✔
6252

6253
  SInputColumnInfoData* pInput = &pCtx->input;
9,515,765✔
6254
  SColumnInfoData*      pCol = pInput->pData[0];
9,515,765✔
6255

6256
  int32_t type = pCol->info.type;
9,516,308✔
6257
  int32_t bytes = pCol->info.bytes;
9,515,222✔
6258

6259
  int32_t start = pInput->startRowIndex;
9,516,308✔
6260
  int32_t numOfRows = pInput->numOfRows;
9,515,222✔
6261

6262
  int32_t numOfElems = 0;
9,516,851✔
6263
  if (IS_NULL_TYPE(type)) {
9,516,851✔
6264
    goto _hll_over;
141,731✔
6265
  }
6266

6267
  for (int32_t i = start; i < numOfRows + start; ++i) {
730,367,681✔
6268
    if (pCol->hasNull && colDataIsNull_s(pCol, i)) {
861,749,737✔
6269
      continue;
134,087,354✔
6270
    }
6271

6272
    numOfElems++;
586,902,476✔
6273

6274
    char* data = colDataGetData(pCol, i);
586,902,476✔
6275
    if (IS_VAR_DATA_TYPE(type)) {
586,929,083✔
6276
      if (IS_STR_DATA_BLOB(type)) {
77,238,399✔
UNCOV
6277
        bytes = blobDataLen(data);
×
6278
        data = blobDataVal(data);
×
6279
      } else {
6280
        bytes = varDataLen(data);
77,238,942✔
6281
        data = varDataVal(data);
77,238,942✔
6282
      }
6283
    }
6284

6285
    int32_t index = 0;
586,929,626✔
6286
    uint8_t count = hllCountNum(data, bytes, &index);
586,926,368✔
6287
    uint8_t oldcount = pInfo->buckets[index];
586,904,105✔
6288
    if (count > oldcount) {
586,906,277✔
6289
      pInfo->buckets[index] = count;
73,177,852✔
6290
    }
6291
  }
6292

6293
_hll_over:
9,373,491✔
6294
  pInfo->totalCount += numOfElems;
9,515,222✔
6295

6296
  if (pInfo->totalCount == 0 && !tsCountAlwaysReturnValue) {
9,516,851✔
6297
    SET_VAL(GET_RES_INFO(pCtx), 0, 1);
495,783✔
6298
  } else {
6299
    SET_VAL(GET_RES_INFO(pCtx), 1, 1);
9,020,525✔
6300
  }
6301

6302
  return TSDB_CODE_SUCCESS;
9,515,765✔
6303
}
6304

6305
static void hllTransferInfo(SHLLInfo* pInput, SHLLInfo* pOutput) {
264,221✔
6306
  for (int32_t k = 0; k < HLL_BUCKETS; ++k) {
2,147,483,647✔
6307
    if (pOutput->buckets[k] < pInput->buckets[k]) {
2,147,483,647✔
6308
      pOutput->buckets[k] = pInput->buckets[k];
21,835,326✔
6309
    }
6310
  }
6311
  pOutput->totalCount += pInput->totalCount;
3,679✔
6312
}
264,221✔
6313

6314
int32_t hllFunctionMerge(SqlFunctionCtx* pCtx) {
264,221✔
6315
  SInputColumnInfoData* pInput = &pCtx->input;
264,221✔
6316
  SColumnInfoData*      pCol = pInput->pData[0];
264,221✔
6317

6318
  if (IS_NULL_TYPE(pCol->info.type)) {
264,221✔
6319
    SET_VAL(GET_RES_INFO(pCtx), 0, 1);
×
6320
    return TSDB_CODE_SUCCESS;
×
6321
  }
6322

6323
  if (pCol->info.type != TSDB_DATA_TYPE_BINARY) {
264,221✔
6324
    return TSDB_CODE_SUCCESS;
×
6325
  }
6326

6327
  SHLLInfo* pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
264,221✔
6328

6329
  int32_t start = pInput->startRowIndex;
264,221✔
6330

6331
  for (int32_t i = start; i < start + pInput->numOfRows; ++i) {
528,442✔
6332
    if (colDataIsNull_s(pCol, i)) continue;
528,442✔
6333
    char*     data = colDataGetData(pCol, i);
264,221✔
6334
    SHLLInfo* pInputInfo = (SHLLInfo*)varDataVal(data);
264,221✔
6335
    hllTransferInfo(pInputInfo, pInfo);
264,221✔
6336
  }
6337

6338
  if (pInfo->totalCount == 0 && !tsCountAlwaysReturnValue) {
264,221✔
6339
    SET_VAL(GET_RES_INFO(pCtx), 0, 1);
63✔
6340
  } else {
6341
    SET_VAL(GET_RES_INFO(pCtx), 1, 1);
264,158✔
6342
  }
6343

6344
  return TSDB_CODE_SUCCESS;
264,221✔
6345
}
6346

6347
int32_t hllFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
9,260,800✔
6348
  SResultRowEntryInfo* pInfo = GET_RES_INFO(pCtx);
9,260,800✔
6349

6350
  SHLLInfo* pHllInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
9,260,800✔
6351
  pHllInfo->result = hllCountCnt(pHllInfo->buckets);
9,260,800✔
6352
  if (tsCountAlwaysReturnValue && pHllInfo->result == 0) {
9,260,800✔
6353
    pInfo->numOfRes = 1;
323,869✔
6354
  }
6355

6356
  return functionFinalize(pCtx, pBlock);
9,260,800✔
6357
}
6358

6359
int32_t hllPartialFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
264,221✔
6360
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
264,221✔
6361
  SHLLInfo*            pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
264,221✔
6362
  int32_t              resultBytes = getHLLInfoSize();
264,221✔
6363
  char*                res = taosMemoryCalloc(resultBytes + VARSTR_HEADER_SIZE, sizeof(char));
264,221✔
6364

6365
  if (NULL == res) {
264,221✔
6366
    return terrno;
×
6367
  }
6368
  (void)memcpy(varDataVal(res), pInfo, resultBytes);
264,221✔
6369
  varDataSetLen(res, resultBytes);
264,221✔
6370

6371
  int32_t          slotId = pCtx->pExpr->base.resSchema.slotId;
264,221✔
6372
  int32_t          code = TSDB_CODE_SUCCESS;
264,221✔
6373
  SColumnInfoData* pCol = taosArrayGet(pBlock->pDataBlock, slotId);
264,221✔
6374
  if (NULL == pCol) {
264,221✔
6375
    code = terrno;
×
6376
    goto _exit;
×
6377
  }
6378

6379
  code = colDataSetVal(pCol, pBlock->info.rows, res, false);
264,221✔
6380

6381
_exit:
264,221✔
6382
  taosMemoryFree(res);
264,221✔
6383
  return code;
264,221✔
6384
}
6385

6386
int32_t hllCombine(SqlFunctionCtx* pDestCtx, SqlFunctionCtx* pSourceCtx) {
×
6387
  SResultRowEntryInfo* pDResInfo = GET_RES_INFO(pDestCtx);
×
6388
  SHLLInfo*            pDBuf = GET_ROWCELL_INTERBUF(pDResInfo);
×
6389

6390
  SResultRowEntryInfo* pSResInfo = GET_RES_INFO(pSourceCtx);
×
6391
  SHLLInfo*            pSBuf = GET_ROWCELL_INTERBUF(pSResInfo);
×
6392

6393
  hllTransferInfo(pSBuf, pDBuf);
×
6394
  pDResInfo->numOfRes = TMAX(pDResInfo->numOfRes, pSResInfo->numOfRes);
×
6395
  pDResInfo->isNullRes &= pSResInfo->isNullRes;
×
6396
  return TSDB_CODE_SUCCESS;
×
6397
}
6398

6399
bool getStateFuncEnv(SFunctionNode* UNUSED_PARAM(pFunc), SFuncExecEnv* pEnv) {
1,335,681✔
6400
  pEnv->calcMemSize = sizeof(SStateInfo);
1,335,681✔
6401
  return true;
1,335,681✔
6402
}
6403

6404
static int8_t getStateOpType(char* opStr) {
1,358,027✔
6405
  int8_t opType;
6406
  if (strncasecmp(opStr, "LT", 2) == 0) {
1,358,027✔
6407
    opType = STATE_OPER_LT;
412,008✔
6408
  } else if (strncasecmp(opStr, "GT", 2) == 0) {
946,019✔
6409
    opType = STATE_OPER_GT;
210,932✔
6410
  } else if (strncasecmp(opStr, "LE", 2) == 0) {
735,087✔
6411
    opType = STATE_OPER_LE;
113,622✔
6412
  } else if (strncasecmp(opStr, "GE", 2) == 0) {
621,465✔
6413
    opType = STATE_OPER_GE;
111,740✔
6414
  } else if (strncasecmp(opStr, "NE", 2) == 0) {
509,725✔
6415
    opType = STATE_OPER_NE;
366,583✔
6416
  } else if (strncasecmp(opStr, "EQ", 2) == 0) {
143,142✔
6417
    opType = STATE_OPER_EQ;
143,142✔
6418
  } else {
UNCOV
6419
    opType = STATE_OPER_INVALID;
×
6420
  }
6421

6422
  return opType;
1,358,027✔
6423
}
6424

6425
static bool checkStateOp(int8_t op, SColumnInfoData* pCol, int32_t index, SVariant param) {
140,185,363✔
6426
  char* data = colDataGetData(pCol, index);
140,185,363✔
6427
  switch (pCol->info.type) {
140,184,833✔
6428
    case TSDB_DATA_TYPE_TINYINT: {
20,934,234✔
6429
      int8_t v = *(int8_t*)data;
20,934,234✔
6430
      STATE_COMP(op, v, param);
20,934,234✔
6431
      break;
×
6432
    }
6433
    case TSDB_DATA_TYPE_UTINYINT: {
30,969,568✔
6434
      uint8_t v = *(uint8_t*)data;
30,969,568✔
6435
      STATE_COMP(op, v, param);
30,969,568✔
6436
      break;
×
6437
    }
6438
    case TSDB_DATA_TYPE_SMALLINT: {
686,988✔
6439
      int16_t v = *(int16_t*)data;
686,988✔
6440
      STATE_COMP(op, v, param);
686,988✔
6441
      break;
×
6442
    }
6443
    case TSDB_DATA_TYPE_USMALLINT: {
626,400✔
6444
      uint16_t v = *(uint16_t*)data;
626,400✔
6445
      STATE_COMP(op, v, param);
626,400✔
6446
      break;
×
6447
    }
6448
    case TSDB_DATA_TYPE_INT: {
28,577,324✔
6449
      int32_t v = *(int32_t*)data;
28,577,324✔
6450
      STATE_COMP(op, v, param);
28,577,324✔
6451
      break;
×
6452
    }
6453
    case TSDB_DATA_TYPE_UINT: {
626,400✔
6454
      uint32_t v = *(uint32_t*)data;
626,400✔
6455
      STATE_COMP(op, v, param);
626,400✔
6456
      break;
×
6457
    }
6458
    case TSDB_DATA_TYPE_BIGINT: {
696,627✔
6459
      int64_t v = *(int64_t*)data;
696,627✔
6460
      STATE_COMP(op, v, param);
696,627✔
6461
      break;
×
6462
    }
6463
    case TSDB_DATA_TYPE_UBIGINT: {
626,400✔
6464
      uint64_t v = *(uint64_t*)data;
626,400✔
6465
      STATE_COMP(op, v, param);
626,400✔
6466
      break;
×
6467
    }
6468
    case TSDB_DATA_TYPE_FLOAT: {
32,437,988✔
6469
      float v = *(float*)data;
32,437,988✔
6470
      STATE_COMP(op, v, param);
32,437,988✔
6471
      break;
×
6472
    }
6473
    case TSDB_DATA_TYPE_DOUBLE: {
24,003,434✔
6474
      double v = *(double*)data;
24,003,434✔
6475
      STATE_COMP(op, v, param);
24,003,434✔
6476
      break;
×
6477
    }
6478
    default: {
×
6479
      return false;
×
6480
    }
6481
  }
6482
  return false;
×
6483
}
6484

6485
int32_t stateCountFunction(SqlFunctionCtx* pCtx) {
415,933✔
6486
  int32_t              code = TSDB_CODE_SUCCESS;
415,933✔
6487
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
415,933✔
6488
  SStateInfo*          pInfo = GET_ROWCELL_INTERBUF(pResInfo);
415,933✔
6489

6490
  SInputColumnInfoData* pInput = &pCtx->input;
415,933✔
6491
  TSKEY*                tsList = (int64_t*)pInput->pPTS->pData;
415,933✔
6492

6493
  SColumnInfoData* pInputCol = pInput->pData[0];
415,933✔
6494

6495
  int32_t          numOfElems = 0;
415,933✔
6496
  SColumnInfoData* pOutput = (SColumnInfoData*)pCtx->pOutput;
415,933✔
6497

6498
  int8_t op = getStateOpType(varDataVal(pCtx->param[1].param.pz));
415,933✔
6499
  if (STATE_OPER_INVALID == op) {
415,933✔
6500
    return 0;
×
6501
  }
6502

6503
  for (int32_t i = pInput->startRowIndex; i < pInput->numOfRows + pInput->startRowIndex; i += 1) {
102,587,621✔
6504
    if (pInfo->isPrevTsSet == true && tsList[i] == pInfo->prevTs) {
102,172,532✔
6505
      return TSDB_CODE_FUNC_DUP_TIMESTAMP;
844✔
6506
    } else {
6507
      pInfo->prevTs = tsList[i];
102,170,628✔
6508
    }
6509

6510
    pInfo->isPrevTsSet = true;
102,171,688✔
6511
    numOfElems++;
102,172,218✔
6512

6513
    if (colDataIsNull_f(pInputCol, i)) {
102,172,218✔
6514
      colDataSetNULL(pOutput, i);
23,349,496✔
6515
      // handle selectivity
6516
      if (pCtx->subsidiaries.num > 0) {
23,349,496✔
6517
        code = appendSelectivityValue(pCtx, i, pCtx->offset + numOfElems - 1);
3,969✔
6518
        if (TSDB_CODE_SUCCESS != code) {
3,969✔
6519
          return code;
×
6520
        }
6521
      }
6522
      continue;
23,349,496✔
6523
    }
6524

6525
    bool ret = checkStateOp(op, pInputCol, i, pCtx->param[2].param);
78,822,722✔
6526

6527
    int64_t output = -1;
78,822,722✔
6528
    if (ret) {
78,822,722✔
6529
      output = ++pInfo->count;
47,997,251✔
6530
    } else {
6531
      pInfo->count = 0;
30,825,471✔
6532
    }
6533
    code = colDataSetVal(pOutput, pCtx->offset + numOfElems - 1, (char*)&output, false);
78,822,722✔
6534
    if (TSDB_CODE_SUCCESS != code) {
78,822,192✔
6535
      return code;
×
6536
    }
6537

6538
    // handle selectivity
6539
    if (pCtx->subsidiaries.num > 0) {
78,822,192✔
6540
      code = appendSelectivityValue(pCtx, i, pCtx->offset + numOfElems - 1);
838,288✔
6541
      if (TSDB_CODE_SUCCESS != code) {
838,288✔
6542
        return code;
×
6543
      }
6544
    }
6545
  }
6546

6547
  pResInfo->numOfRes = numOfElems;
415,089✔
6548
  return TSDB_CODE_SUCCESS;
415,089✔
6549
}
6550

6551
int32_t stateDurationFunction(SqlFunctionCtx* pCtx) {
942,094✔
6552
  int32_t              code = TSDB_CODE_SUCCESS;
942,094✔
6553
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
942,094✔
6554
  SStateInfo*          pInfo = GET_ROWCELL_INTERBUF(pResInfo);
942,094✔
6555

6556
  SInputColumnInfoData* pInput = &pCtx->input;
942,094✔
6557
  TSKEY*                tsList = (int64_t*)pInput->pPTS->pData;
942,094✔
6558

6559
  SColumnInfoData* pInputCol = pInput->pData[0];
942,094✔
6560

6561
  int32_t          numOfElems = 0;
942,094✔
6562
  SColumnInfoData* pOutput = (SColumnInfoData*)pCtx->pOutput;
942,094✔
6563

6564
  // TODO: process timeUnit for different db precisions
6565
  int32_t timeUnit = 1;
942,094✔
6566
  if (pCtx->numOfParams == 5) {  // TODO: param number incorrect
942,094✔
6567
    timeUnit = pCtx->param[3].param.i;
727,185✔
6568
  }
6569

6570
  int8_t op = getStateOpType(varDataVal(pCtx->param[1].param.pz));
942,094✔
6571
  if (STATE_OPER_INVALID == op) {
942,529✔
6572
    return TSDB_CODE_INVALID_PARA;
×
6573
  }
6574

6575
  for (int32_t i = pInput->startRowIndex; i < pInput->numOfRows + pInput->startRowIndex; i += 1) {
66,976,311✔
6576
    if (pInfo->isPrevTsSet == true && tsList[i] == pInfo->prevTs) {
66,034,626✔
6577
      return TSDB_CODE_FUNC_DUP_TIMESTAMP;
844✔
6578
    } else {
6579
      pInfo->prevTs = tsList[i];
66,033,347✔
6580
    }
6581

6582
    pInfo->isPrevTsSet = true;
66,034,217✔
6583
    numOfElems++;
66,033,782✔
6584

6585
    if (colDataIsNull_f(pInputCol, i)) {
66,033,782✔
6586
      colDataSetNULL(pOutput, i);
4,671,141✔
6587
      // handle selectivity
6588
      if (pCtx->subsidiaries.num > 0) {
4,671,576✔
6589
        code = appendSelectivityValue(pCtx, i, pCtx->offset + numOfElems - 1);
7,713✔
6590
        if (TSDB_CODE_SUCCESS != code) {
7,713✔
6591
          return code;
×
6592
        }
6593
      }
6594
      continue;
4,671,576✔
6595
    }
6596

6597
    bool    ret = checkStateOp(op, pInputCol, i, pCtx->param[2].param);
61,362,641✔
6598
    int64_t output = -1;
61,362,641✔
6599
    if (ret) {
61,362,641✔
6600
      if (pInfo->durationStart == 0) {
40,863,518✔
6601
        output = 0;
4,428,352✔
6602
        pInfo->durationStart = tsList[i];
4,428,352✔
6603
      } else {
6604
        output = (tsList[i] - pInfo->durationStart) / timeUnit;
36,435,166✔
6605
      }
6606
    } else {
6607
      pInfo->durationStart = 0;
20,499,123✔
6608
    }
6609
    code = colDataSetVal(pOutput, pCtx->offset + numOfElems - 1, (char*)&output, false);
61,362,206✔
6610
    if (TSDB_CODE_SUCCESS != code) {
61,362,641✔
6611
      return code;
×
6612
    }
6613

6614
    // handle selectivity
6615
    if (pCtx->subsidiaries.num > 0) {
61,362,641✔
6616
      code = appendSelectivityValue(pCtx, i, pCtx->offset + numOfElems - 1);
95,764✔
6617
      if (TSDB_CODE_SUCCESS != code) {
95,329✔
6618
        return code;
×
6619
      }
6620
    }
6621
  }
6622

6623
  pResInfo->numOfRes = numOfElems;
941,685✔
6624
  return TSDB_CODE_SUCCESS;
941,685✔
6625
}
6626

6627
bool getCsumFuncEnv(SFunctionNode* UNUSED_PARAM(pFunc), SFuncExecEnv* pEnv) {
670,179✔
6628
  pEnv->calcMemSize = sizeof(SSumRes);
670,179✔
6629
  return true;
670,179✔
6630
}
6631

6632
int32_t csumFunction(SqlFunctionCtx* pCtx) {
751,370✔
6633
  int32_t              code = TSDB_CODE_SUCCESS;
751,370✔
6634
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
751,370✔
6635
  SSumRes*             pSumRes = GET_ROWCELL_INTERBUF(pResInfo);
751,745✔
6636

6637
  SInputColumnInfoData* pInput = &pCtx->input;
751,745✔
6638
  TSKEY*                tsList = (int64_t*)pInput->pPTS->pData;
751,370✔
6639

6640
  SColumnInfoData* pInputCol = pInput->pData[0];
751,370✔
6641
  SColumnInfoData* pOutput = (SColumnInfoData*)pCtx->pOutput;
751,745✔
6642

6643
  int32_t numOfElems = 0;
751,745✔
6644
  int32_t type = pInputCol->info.type;
751,745✔
6645
  int32_t startOffset = pCtx->offset;
751,370✔
6646
  for (int32_t i = pInput->startRowIndex; i < pInput->numOfRows + pInput->startRowIndex; i += 1) {
126,443,533✔
6647
    if (pSumRes->isPrevTsSet == true && tsList[i] == pSumRes->prevTs) {
125,698,988✔
6648
      return TSDB_CODE_FUNC_DUP_TIMESTAMP;
7,200✔
6649
    } else {
6650
      pSumRes->prevTs = tsList[i];
125,690,663✔
6651
    }
6652
    pSumRes->isPrevTsSet = true;
125,692,538✔
6653

6654
    int32_t pos = startOffset + numOfElems;
125,692,163✔
6655
    if (colDataIsNull_f(pInputCol, i)) {
125,692,163✔
6656
      // colDataSetNULL(pOutput, i);
6657
      continue;
107,381,801✔
6658
    }
6659

6660
    char* data = colDataGetData(pInputCol, i);
18,310,362✔
6661
    if (IS_SIGNED_NUMERIC_TYPE(type)) {
23,816,104✔
6662
      int64_t v;
6663
      GET_TYPED_DATA(v, int64_t, type, data, typeGetTypeModFromColInfo(&pInputCol->info));
5,505,742✔
6664
      pSumRes->isum += v;
5,505,742✔
6665
      code = colDataSetVal(pOutput, pos, (char*)&pSumRes->isum, false);
5,505,742✔
6666
      if (TSDB_CODE_SUCCESS != code) {
5,505,742✔
6667
        return code;
×
6668
      }
6669
    } else if (IS_UNSIGNED_NUMERIC_TYPE(type)) {
23,037,840✔
6670
      uint64_t v;
6671
      GET_TYPED_DATA(v, uint64_t, type, data, typeGetTypeModFromColInfo(&pInputCol->info));
10,233,220✔
6672
      pSumRes->usum += v;
10,233,220✔
6673
      code = colDataSetVal(pOutput, pos, (char*)&pSumRes->usum, false);
10,233,220✔
6674
      if (TSDB_CODE_SUCCESS != code) {
10,233,220✔
6675
        return code;
×
6676
      }
6677
    } else if (IS_FLOAT_TYPE(type)) {
2,571,400✔
6678
      double v;
6679
      GET_TYPED_DATA(v, double, type, data, typeGetTypeModFromColInfo(&pInputCol->info));
2,571,400✔
6680
      pSumRes->dsum += v;
2,571,400✔
6681
      // check for overflow
6682
      if (isinf(pSumRes->dsum) || isnan(pSumRes->dsum)) {
2,571,400✔
6683
        colDataSetNULL(pOutput, pos);
884✔
6684
      } else {
6685
        code = colDataSetVal(pOutput, pos, (char*)&pSumRes->dsum, false);
2,570,516✔
6686
        if (TSDB_CODE_SUCCESS != code) {
2,570,516✔
6687
          return code;
×
6688
        }
6689
      }
6690
    }
6691

6692
    // handle selectivity
6693
    if (pCtx->subsidiaries.num > 0) {
18,310,362✔
6694
      code = appendSelectivityValue(pCtx, i, pos);
22,706✔
6695
      if (TSDB_CODE_SUCCESS != code) {
22,706✔
6696
        return code;
×
6697
      }
6698
    }
6699

6700
    numOfElems++;
18,310,362✔
6701
  }
6702

6703
  pResInfo->numOfRes = numOfElems;
744,545✔
6704
  return TSDB_CODE_SUCCESS;
744,545✔
6705
}
6706

6707
bool getMavgFuncEnv(SFunctionNode* UNUSED_PARAM(pFunc), SFuncExecEnv* pEnv) {
389,924✔
6708
  pEnv->calcMemSize = sizeof(SMavgInfo) + MAVG_MAX_POINTS_NUM * sizeof(double);
389,924✔
6709
  return true;
390,451✔
6710
}
6711

6712
int32_t mavgFunctionSetup(SqlFunctionCtx* pCtx, SResultRowEntryInfo* pResultInfo) {
865,025✔
6713
  if (pResultInfo->initialized) {
865,025✔
6714
    return TSDB_CODE_SUCCESS;
384,538✔
6715
  }
6716
  if (TSDB_CODE_SUCCESS != functionSetup(pCtx, pResultInfo)) {
480,487✔
6717
    return TSDB_CODE_FUNC_SETUP_ERROR;
×
6718
  }
6719

6720
  SMavgInfo* pInfo = GET_ROWCELL_INTERBUF(pResultInfo);
480,487✔
6721
  pInfo->pos = 0;
480,487✔
6722
  pInfo->sum = 0;
480,487✔
6723
  pInfo->prevTs = -1;
480,487✔
6724
  pInfo->isPrevTsSet = false;
480,487✔
6725
  pInfo->numOfPoints = pCtx->param[1].param.i;
480,487✔
6726
  if (pInfo->numOfPoints < 1 || pInfo->numOfPoints > MAVG_MAX_POINTS_NUM) {
480,487✔
6727
    return TSDB_CODE_FUNC_FUNTION_PARA_VALUE;
×
6728
  }
6729
  pInfo->pointsMeet = false;
480,487✔
6730

6731
  return TSDB_CODE_SUCCESS;
480,487✔
6732
}
6733

6734
int32_t mavgFunction(SqlFunctionCtx* pCtx) {
474,574✔
6735
  int32_t              code = TSDB_CODE_SUCCESS;
474,574✔
6736
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
474,574✔
6737
  SMavgInfo*           pInfo = GET_ROWCELL_INTERBUF(pResInfo);
474,574✔
6738

6739
  SInputColumnInfoData* pInput = &pCtx->input;
474,574✔
6740
  TSKEY*                tsList = (int64_t*)pInput->pPTS->pData;
474,574✔
6741

6742
  SColumnInfoData* pInputCol = pInput->pData[0];
474,574✔
6743
  SColumnInfoData* pTsOutput = pCtx->pTsOutput;
474,574✔
6744
  SColumnInfoData* pOutput = (SColumnInfoData*)pCtx->pOutput;
474,574✔
6745

6746
  int32_t numOfElems = 0;
474,574✔
6747
  int32_t type = pInputCol->info.type;
474,574✔
6748
  int32_t startOffset = pCtx->offset;
474,574✔
6749
  for (int32_t i = pInput->startRowIndex; i < pInput->numOfRows + pInput->startRowIndex; i += 1) {
123,045,015✔
6750
    if (pInfo->isPrevTsSet == true && tsList[i] == pInfo->prevTs) {
122,578,355✔
6751
      return TSDB_CODE_FUNC_DUP_TIMESTAMP;
844✔
6752
    } else {
6753
      pInfo->prevTs = tsList[i];
122,574,481✔
6754
    }
6755
    pInfo->isPrevTsSet = true;
122,576,984✔
6756

6757
    int32_t pos = startOffset + numOfElems;
122,587,106✔
6758
    if (colDataIsNull_f(pInputCol, i)) {
122,587,106✔
6759
      // colDataSetNULL(pOutput, i);
6760
      continue;
33,718,335✔
6761
    }
6762

6763
    char*  data = colDataGetData(pInputCol, i);
88,911,191✔
6764
    double v;
6765
    GET_TYPED_DATA(v, double, type, data, typeGetTypeModFromColInfo(&pInputCol->info));
88,911,191✔
6766

6767
    if (!pInfo->pointsMeet && (pInfo->pos < pInfo->numOfPoints - 1)) {
88,911,191✔
6768
      pInfo->points[pInfo->pos] = v;
21,745,746✔
6769
      pInfo->sum += v;
21,745,746✔
6770
    } else {
6771
      if (!pInfo->pointsMeet && (pInfo->pos == pInfo->numOfPoints - 1)) {
67,165,445✔
6772
        pInfo->sum += v;
244,373✔
6773
        pInfo->pointsMeet = true;
244,373✔
6774
      } else {
6775
        pInfo->sum = pInfo->sum + v - pInfo->points[pInfo->pos];
66,921,072✔
6776
      }
6777

6778
      pInfo->points[pInfo->pos] = v;
67,165,445✔
6779
      double result = pInfo->sum / pInfo->numOfPoints;
67,165,445✔
6780
      // check for overflow
6781
      if (isinf(result) || isnan(result)) {
67,165,445✔
6782
        colDataSetNULL(pOutput, pos);
×
6783
      } else {
6784
        code = colDataSetVal(pOutput, pos, (char*)&result, false);
67,165,445✔
6785
        if (TSDB_CODE_SUCCESS != code) {
67,165,445✔
6786
          return code;
×
6787
        }
6788
      }
6789

6790
      // handle selectivity
6791
      if (pCtx->subsidiaries.num > 0) {
67,165,445✔
6792
        code = appendSelectivityValue(pCtx, i, pos);
33,136✔
6793
        if (TSDB_CODE_SUCCESS != code) {
33,136✔
6794
          return code;
×
6795
        }
6796
      }
6797

6798
      numOfElems++;
67,165,445✔
6799
    }
6800

6801
    pInfo->pos++;
88,911,191✔
6802
    if (pInfo->pos == pInfo->numOfPoints) {
88,911,191✔
6803
      pInfo->pos = 0;
1,031,112✔
6804
    }
6805
  }
6806

6807
  pResInfo->numOfRes = numOfElems;
473,730✔
6808
  return TSDB_CODE_SUCCESS;
473,730✔
6809
}
6810

6811
static SSampleInfo* getSampleOutputInfo(SqlFunctionCtx* pCtx) {
4,191,711✔
6812
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
4,191,711✔
6813
  SSampleInfo*         pInfo = GET_ROWCELL_INTERBUF(pResInfo);
4,191,711✔
6814

6815
  pInfo->data = (char*)pInfo + sizeof(SSampleInfo);
4,191,711✔
6816
  pInfo->tuplePos = (STuplePos*)((char*)pInfo + sizeof(SSampleInfo) + pInfo->samples * pInfo->colBytes);
4,191,711✔
6817

6818
  return pInfo;
4,192,086✔
6819
}
6820

6821
bool getSampleFuncEnv(SFunctionNode* pFunc, SFuncExecEnv* pEnv) {
797,782✔
6822
  SColumnNode* pCol = (SColumnNode*)nodesListGetNode(pFunc->pParameterList, 0);
797,782✔
6823
  SValueNode*  pVal = (SValueNode*)nodesListGetNode(pFunc->pParameterList, 1);
798,687✔
6824
  int32_t      numOfSamples = pVal->datum.i;
796,962✔
6825
  pEnv->calcMemSize = sizeof(SSampleInfo) + numOfSamples * (pCol->node.resType.bytes + sizeof(STuplePos));
796,057✔
6826
  return true;
796,587✔
6827
}
6828

6829
int32_t sampleFunctionSetup(SqlFunctionCtx* pCtx, SResultRowEntryInfo* pResultInfo) {
1,740,500✔
6830
  if (pResultInfo->initialized) {
1,740,500✔
6831
    return TSDB_CODE_SUCCESS;
×
6832
  }
6833
  if (TSDB_CODE_SUCCESS != functionSetup(pCtx, pResultInfo)) {
1,740,500✔
6834
    return TSDB_CODE_FUNC_SETUP_ERROR;
×
6835
  }
6836

6837
  taosSeedRand(taosSafeRand());
1,740,500✔
6838

6839
  SSampleInfo* pInfo = GET_ROWCELL_INTERBUF(pResultInfo);
1,740,500✔
6840
  pInfo->samples = pCtx->param[1].param.i;
1,740,500✔
6841
  pInfo->totalPoints = 0;
1,740,500✔
6842
  pInfo->numSampled = 0;
1,740,500✔
6843
  pInfo->colType = pCtx->resDataInfo.type;
1,740,500✔
6844
  pInfo->colBytes = pCtx->resDataInfo.bytes;
1,740,500✔
6845
  pInfo->nullTuplePos.pageId = -1;
1,740,500✔
6846
  pInfo->nullTupleSaved = false;
1,740,500✔
6847
  pInfo->data = (char*)pInfo + sizeof(SSampleInfo);
1,740,500✔
6848
  pInfo->tuplePos = (STuplePos*)((char*)pInfo + sizeof(SSampleInfo) + pInfo->samples * pInfo->colBytes);
1,740,500✔
6849

6850
  return TSDB_CODE_SUCCESS;
1,740,500✔
6851
}
6852

6853
static void sampleAssignResult(SSampleInfo* pInfo, char* data, int32_t index) {
98,438,813✔
6854
  assignVal(pInfo->data + index * pInfo->colBytes, data, pInfo->colBytes, pInfo->colType);
98,438,813✔
6855
}
98,441,618✔
6856

6857
static int32_t doReservoirSample(SqlFunctionCtx* pCtx, SSampleInfo* pInfo, char* data, int32_t index) {
133,832,538✔
6858
  pInfo->totalPoints++;
133,832,538✔
6859
  if (pInfo->numSampled < pInfo->samples) {
133,833,443✔
6860
    sampleAssignResult(pInfo, data, pInfo->numSampled);
96,928,066✔
6861
    if (pCtx->subsidiaries.num > 0) {
96,922,041✔
6862
      int32_t code = saveTupleData(pCtx, index, pCtx->pSrcBlock, &pInfo->tuplePos[pInfo->numSampled]);
1,008,107✔
6863
      if (code != TSDB_CODE_SUCCESS) {
1,008,107✔
6864
        return code;
×
6865
      }
6866
    }
6867
    pInfo->numSampled++;
96,922,946✔
6868
  } else {
6869
    int32_t j = (int32_t)(taosRand() % (uint64_t)pInfo->totalPoints);
36,908,027✔
6870
    if (j < pInfo->samples) {
36,908,027✔
6871
      sampleAssignResult(pInfo, data, j);
1,516,552✔
6872
      if (pCtx->subsidiaries.num > 0) {
1,516,552✔
6873
        int32_t code = updateTupleData(pCtx, index, pCtx->pSrcBlock, &pInfo->tuplePos[j]);
318,728✔
6874
        if (code != TSDB_CODE_SUCCESS) {
319,103✔
6875
          return code;
×
6876
        }
6877
      }
6878
    }
6879
  }
6880

6881
  return TSDB_CODE_SUCCESS;
133,833,843✔
6882
}
6883

6884
int32_t sampleFunction(SqlFunctionCtx* pCtx) {
2,454,118✔
6885
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
2,454,118✔
6886
  SSampleInfo*         pInfo = getSampleOutputInfo(pCtx);
2,454,118✔
6887

6888
  SInputColumnInfoData* pInput = &pCtx->input;
2,454,118✔
6889

6890
  SColumnInfoData* pInputCol = pInput->pData[0];
2,454,118✔
6891
  for (int32_t i = pInput->startRowIndex; i < pInput->numOfRows + pInput->startRowIndex; i += 1) {
151,467,485✔
6892
    if (colDataIsNull_s(pInputCol, i)) {
298,030,444✔
6893
      continue;
15,178,464✔
6894
    }
6895

6896
    char*   data = colDataGetData(pInputCol, i);
133,838,613✔
6897
    int32_t code = doReservoirSample(pCtx, pInfo, data, i);
133,832,318✔
6898
    if (code != TSDB_CODE_SUCCESS) {
133,834,903✔
6899
      return code;
×
6900
    }
6901
  }
6902

6903
  if (pInfo->numSampled == 0 && pCtx->subsidiaries.num > 0 && !pInfo->nullTupleSaved) {
2,454,118✔
6904
    int32_t code = saveTupleData(pCtx, pInput->startRowIndex, pCtx->pSrcBlock, &pInfo->nullTuplePos);
1,750✔
6905
    if (code != TSDB_CODE_SUCCESS) {
1,750✔
6906
      return code;
×
6907
    }
6908
    pInfo->nullTupleSaved = true;
1,750✔
6909
  }
6910

6911
  SET_VAL(pResInfo, pInfo->numSampled, pInfo->numSampled);
2,454,118✔
6912
  return TSDB_CODE_SUCCESS;
2,454,118✔
6913
}
6914

6915
int32_t sampleFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
1,737,968✔
6916
  int32_t              code = TSDB_CODE_SUCCESS;
1,737,968✔
6917
  SResultRowEntryInfo* pEntryInfo = GET_RES_INFO(pCtx);
1,737,968✔
6918

6919
  SSampleInfo* pInfo = getSampleOutputInfo(pCtx);
1,737,968✔
6920
  pEntryInfo->complete = true;
1,737,968✔
6921

6922
  int32_t          slotId = pCtx->pExpr->base.resSchema.slotId;
1,737,968✔
6923
  SColumnInfoData* pCol = taosArrayGet(pBlock->pDataBlock, slotId);
1,737,968✔
6924
  if (NULL == pCol) {
1,737,063✔
6925
    return TSDB_CODE_OUT_OF_RANGE;
×
6926
  }
6927

6928
  int32_t currentRow = pBlock->info.rows;
1,737,063✔
6929
  if (pInfo->numSampled == 0) {
1,737,063✔
6930
    colDataSetNULL(pCol, currentRow);
136,564✔
6931
    code = setSelectivityValue(pCtx, pBlock, &pInfo->nullTuplePos, currentRow);
136,564✔
6932
    return code;
136,564✔
6933
  }
6934
  for (int32_t i = 0; i < pInfo->numSampled; ++i) {
98,538,815✔
6935
    code = colDataSetVal(pCol, currentRow + i, pInfo->data + i * pInfo->colBytes, false);
96,938,251✔
6936
    if (TSDB_CODE_SUCCESS != code) {
96,931,916✔
6937
      return code;
×
6938
    }
6939
    code = setSelectivityValue(pCtx, pBlock, &pInfo->tuplePos[i], currentRow + i);
96,931,916✔
6940
    if (TSDB_CODE_SUCCESS != code) {
96,937,411✔
6941
      return code;
×
6942
    }
6943
  }
6944

6945
  return code;
1,601,404✔
6946
}
6947

6948
bool getTailFuncEnv(SFunctionNode* pFunc, SFuncExecEnv* pEnv) {
×
6949
#if 0
6950
  SColumnNode* pCol = (SColumnNode*)nodesListGetNode(pFunc->pParameterList, 0);
6951
  SValueNode*  pVal = (SValueNode*)nodesListGetNode(pFunc->pParameterList, 1);
6952
  int32_t      numOfPoints = pVal->datum.i;
6953
  pEnv->calcMemSize = sizeof(STailInfo) + numOfPoints * (POINTER_BYTES + sizeof(STailItem) + pCol->node.resType.bytes);
6954
#endif
6955
  return true;
×
6956
}
6957

6958
int32_t tailFunctionSetup(SqlFunctionCtx* pCtx, SResultRowEntryInfo* pResultInfo) {
×
6959
#if 0
6960
  if (!functionSetup(pCtx, pResultInfo)) {
6961
    return false;
6962
  }
6963

6964
  STailInfo* pInfo = GET_ROWCELL_INTERBUF(pResultInfo);
6965
  pInfo->numAdded = 0;
6966
  pInfo->numOfPoints = pCtx->param[1].param.i;
6967
  if (pCtx->numOfParams == 4) {
6968
    pInfo->offset = pCtx->param[2].param.i;
6969
  } else {
6970
    pInfo->offset = 0;
6971
  }
6972
  pInfo->colType = pCtx->resDataInfo.type;
6973
  pInfo->colBytes = pCtx->resDataInfo.bytes;
6974
  if ((pInfo->numOfPoints < 1 || pInfo->numOfPoints > TAIL_MAX_POINTS_NUM) ||
6975
      (pInfo->numOfPoints < 0 || pInfo->numOfPoints > TAIL_MAX_OFFSET)) {
6976
    return false;
6977
  }
6978

6979
  pInfo->pItems = (STailItem**)((char*)pInfo + sizeof(STailInfo));
6980
  char* pItem = (char*)pInfo->pItems + pInfo->numOfPoints * POINTER_BYTES;
6981

6982
  size_t unitSize = sizeof(STailItem) + pInfo->colBytes;
6983
  for (int32_t i = 0; i < pInfo->numOfPoints; ++i) {
6984
    pInfo->pItems[i] = (STailItem*)(pItem + i * unitSize);
6985
    pInfo->pItems[i]->isNull = false;
6986
  }
6987
#endif
6988
  return TSDB_CODE_SUCCESS;
×
6989
}
6990

6991
static void tailAssignResult(STailItem* pItem, char* data, int32_t colBytes, TSKEY ts, bool isNull) {
×
6992
#if 0
6993
  pItem->timestamp = ts;
6994
  if (isNull) {
6995
    pItem->isNull = true;
6996
  } else {
6997
    pItem->isNull = false;
6998
    memcpy(pItem->data, data, colBytes);
6999
  }
7000
#endif
7001
}
×
7002

7003
#if 0
7004
static int32_t tailCompFn(const void* p1, const void* p2, const void* param) {
7005
  STailItem* d1 = *(STailItem**)p1;
7006
  STailItem* d2 = *(STailItem**)p2;
7007
  return compareInt64Val(&d1->timestamp, &d2->timestamp);
7008
}
7009

7010
static void doTailAdd(STailInfo* pInfo, char* data, TSKEY ts, bool isNull) {
7011
  STailItem** pList = pInfo->pItems;
7012
  if (pInfo->numAdded < pInfo->numOfPoints) {
7013
    tailAssignResult(pList[pInfo->numAdded], data, pInfo->colBytes, ts, isNull);
7014
    taosheapsort((void*)pList, sizeof(STailItem**), pInfo->numAdded + 1, NULL, tailCompFn, 0);
7015
    pInfo->numAdded++;
7016
  } else if (pList[0]->timestamp < ts) {
7017
    tailAssignResult(pList[0], data, pInfo->colBytes, ts, isNull);
7018
    taosheapadjust((void*)pList, sizeof(STailItem**), 0, pInfo->numOfPoints - 1, NULL, tailCompFn, NULL, 0);
7019
  }
7020
}
7021
#endif
7022

7023
int32_t tailFunction(SqlFunctionCtx* pCtx) {
×
7024
#if 0
7025
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
7026
  STailInfo*           pInfo = GET_ROWCELL_INTERBUF(pResInfo);
7027

7028
  SInputColumnInfoData* pInput = &pCtx->input;
7029
  TSKEY*                tsList = (int64_t*)pInput->pPTS->pData;
7030

7031
  SColumnInfoData* pInputCol = pInput->pData[0];
7032
  SColumnInfoData* pOutput = (SColumnInfoData*)pCtx->pOutput;
7033

7034
  int32_t startOffset = pCtx->offset;
7035
  if (pInfo->offset >= pInput->numOfRows) {
7036
    return 0;
7037
  } else {
7038
    pInfo->numOfPoints = TMIN(pInfo->numOfPoints, pInput->numOfRows - pInfo->offset);
7039
  }
7040
  for (int32_t i = pInput->startRowIndex; i < pInput->numOfRows + pInput->startRowIndex - pInfo->offset; i += 1) {
7041
    char* data = colDataGetData(pInputCol, i);
7042
    doTailAdd(pInfo, data, tsList[i], colDataIsNull_s(pInputCol, i));
7043
  }
7044

7045
  taosqsort(pInfo->pItems, pInfo->numOfPoints, POINTER_BYTES, NULL, tailCompFn);
7046

7047
  for (int32_t i = 0; i < pInfo->numOfPoints; ++i) {
7048
    int32_t    pos = startOffset + i;
7049
    STailItem* pItem = pInfo->pItems[i];
7050
    if (pItem->isNull) {
7051
      colDataSetNULL(pOutput, pos);
7052
    } else {
7053
      colDataSetVal(pOutput, pos, pItem->data, false);
7054
    }
7055
  }
7056

7057
  return pInfo->numOfPoints;
7058
#endif
7059
  return 0;
×
7060
}
7061

7062
int32_t tailFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
×
7063
#if 0
7064
  SResultRowEntryInfo* pEntryInfo = GET_RES_INFO(pCtx);
7065
  STailInfo*           pInfo = GET_ROWCELL_INTERBUF(pEntryInfo);
7066
  pEntryInfo->complete = true;
7067

7068
  int32_t type = pCtx->input.pData[0]->info.type;
7069
  int32_t slotId = pCtx->pExpr->base.resSchema.slotId;
7070

7071
  SColumnInfoData* pCol = taosArrayGet(pBlock->pDataBlock, slotId);
7072

7073
  // todo assign the tag value and the corresponding row data
7074
  int32_t currentRow = pBlock->info.rows;
7075
  for (int32_t i = 0; i < pEntryInfo->numOfRes; ++i) {
7076
    STailItem* pItem = pInfo->pItems[i];
7077
    colDataSetVal(pCol, currentRow, pItem->data, false);
7078
    currentRow += 1;
7079
  }
7080

7081
  return pEntryInfo->numOfRes;
7082
#endif
7083
  return 0;
×
7084
}
7085

7086
bool getUniqueFuncEnv(SFunctionNode* pFunc, SFuncExecEnv* pEnv) {
×
7087
#if 0
7088
  pEnv->calcMemSize = sizeof(SUniqueInfo) + UNIQUE_MAX_RESULT_SIZE;
7089
#endif
7090
  return true;
×
7091
}
7092

7093
int32_t uniqueFunctionSetup(SqlFunctionCtx* pCtx, SResultRowEntryInfo* pResInfo) {
×
7094
#if 0
7095
  if (!functionSetup(pCtx, pResInfo)) {
7096
    return false;
7097
  }
7098

7099
  SUniqueInfo* pInfo = GET_ROWCELL_INTERBUF(pResInfo);
7100
  pInfo->numOfPoints = 0;
7101
  pInfo->colType = pCtx->resDataInfo.type;
7102
  pInfo->colBytes = pCtx->resDataInfo.bytes;
7103
  if (pInfo->pHash != NULL) {
7104
    taosHashClear(pInfo->pHash);
7105
  } else {
7106
    pInfo->pHash = taosHashInit(64, taosGetDefaultHashFunction(TSDB_DATA_TYPE_BINARY), true, HASH_NO_LOCK);
7107
  }
7108
#endif
7109
  return TSDB_CODE_SUCCESS;
×
7110
}
7111

7112
#if 0
7113
static void doUniqueAdd(SUniqueInfo* pInfo, char* data, TSKEY ts, bool isNull) {
7114
  // handle null elements
7115
  if (isNull == true) {
7116
    int32_t      size = sizeof(SUniqueItem) + pInfo->colBytes;
7117
    SUniqueItem* pItem = (SUniqueItem*)(pInfo->pItems + pInfo->numOfPoints * size);
7118
    if (pInfo->hasNull == false && pItem->isNull == false) {
7119
      pItem->timestamp = ts;
7120
      pItem->isNull = true;
7121
      pInfo->numOfPoints++;
7122
      pInfo->hasNull = true;
7123
    } else if (pItem->timestamp > ts && pItem->isNull == true) {
7124
      pItem->timestamp = ts;
7125
    }
7126
    return;
7127
  }
7128

7129
  int32_t      hashKeyBytes = IS_VAR_DATA_TYPE(pInfo->colType) ? varDataTLen(data) : pInfo->colBytes;
7130
  SUniqueItem* pHashItem = taosHashGet(pInfo->pHash, data, hashKeyBytes);
7131
  if (pHashItem == NULL) {
7132
    int32_t      size = sizeof(SUniqueItem) + pInfo->colBytes;
7133
    SUniqueItem* pItem = (SUniqueItem*)(pInfo->pItems + pInfo->numOfPoints * size);
7134
    pItem->timestamp = ts;
7135
    memcpy(pItem->data, data, pInfo->colBytes);
7136

7137
    taosHashPut(pInfo->pHash, data, hashKeyBytes, (char*)pItem, sizeof(SUniqueItem*));
7138
    pInfo->numOfPoints++;
7139
  } else if (pHashItem->timestamp > ts) {
7140
    pHashItem->timestamp = ts;
7141
  }
7142
}
7143
#endif
7144

7145
int32_t uniqueFunction(SqlFunctionCtx* pCtx) {
×
7146
#if 0
7147
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
7148
  SUniqueInfo*         pInfo = GET_ROWCELL_INTERBUF(pResInfo);
7149

7150
  SInputColumnInfoData* pInput = &pCtx->input;
7151
  TSKEY*                tsList = (int64_t*)pInput->pPTS->pData;
7152

7153
  SColumnInfoData* pInputCol = pInput->pData[0];
7154
  SColumnInfoData* pTsOutput = pCtx->pTsOutput;
7155
  SColumnInfoData* pOutput = (SColumnInfoData*)pCtx->pOutput;
7156

7157
  int32_t startOffset = pCtx->offset;
7158
  for (int32_t i = pInput->startRowIndex; i < pInput->numOfRows + pInput->startRowIndex; ++i) {
7159
    char* data = colDataGetData(pInputCol, i);
7160
    doUniqueAdd(pInfo, data, tsList[i], colDataIsNull_s(pInputCol, i));
7161

7162
    if (sizeof(SUniqueInfo) + pInfo->numOfPoints * (sizeof(SUniqueItem) + pInfo->colBytes) >= UNIQUE_MAX_RESULT_SIZE) {
7163
      taosHashCleanup(pInfo->pHash);
7164
      return 0;
7165
    }
7166
  }
7167

7168
  for (int32_t i = 0; i < pInfo->numOfPoints; ++i) {
7169
    SUniqueItem* pItem = (SUniqueItem*)(pInfo->pItems + i * (sizeof(SUniqueItem) + pInfo->colBytes));
7170
    if (pItem->isNull == true) {
7171
      colDataSetNULL(pOutput, i);
7172
    } else {
7173
      colDataSetVal(pOutput, i, pItem->data, false);
7174
    }
7175
    if (pTsOutput != NULL) {
7176
      colDataSetInt64(pTsOutput, i, &pItem->timestamp);
7177
    }
7178
  }
7179

7180
  return pInfo->numOfPoints;
7181
#endif
7182
  return 0;
×
7183
}
7184

7185
bool getModeFuncEnv(SFunctionNode* pFunc, SFuncExecEnv* pEnv) {
774,283✔
7186
  pEnv->calcMemSize = sizeof(SModeInfo);
774,283✔
7187
  return true;
774,283✔
7188
}
7189

7190
int32_t modeFunctionSetup(SqlFunctionCtx* pCtx, SResultRowEntryInfo* pResInfo) {
945,596✔
7191
  if (pResInfo->initialized) {
945,596✔
7192
    return TSDB_CODE_SUCCESS;
×
7193
  }
7194
  if (TSDB_CODE_SUCCESS != functionSetup(pCtx, pResInfo)) {
945,596✔
7195
    return TSDB_CODE_FUNC_SETUP_ERROR;
×
7196
  }
7197

7198
  SModeInfo* pInfo = GET_ROWCELL_INTERBUF(pResInfo);
945,596✔
7199
  pInfo->colType = pCtx->resDataInfo.type;
945,596✔
7200
  pInfo->colBytes = pCtx->resDataInfo.bytes;
945,596✔
7201
  if (pInfo->pHash != NULL) {
945,596✔
7202
    taosHashClear(pInfo->pHash);
×
7203
  } else {
7204
    pInfo->pHash = taosHashInit(64, taosGetDefaultHashFunction(TSDB_DATA_TYPE_BINARY), true, HASH_NO_LOCK);
945,596✔
7205
    if (NULL == pInfo->pHash) {
945,596✔
7206
      return terrno;
×
7207
    }
7208
  }
7209
  pInfo->nullTupleSaved = false;
945,596✔
7210
  pInfo->nullTuplePos.pageId = -1;
945,596✔
7211

7212
  pInfo->buf = taosMemoryMalloc(pInfo->colBytes);
945,596✔
7213
  if (NULL == pInfo->buf) {
945,596✔
7214
    taosHashCleanup(pInfo->pHash);
×
7215
    pInfo->pHash = NULL;
×
7216
    return terrno;
×
7217
  }
7218
  pCtx->needCleanup = true;
945,596✔
7219
  return TSDB_CODE_SUCCESS;
945,596✔
7220
}
7221

7222
static void modeFunctionCleanup(SModeInfo* pInfo) {
1,650,427✔
7223
  taosHashCleanup(pInfo->pHash);
1,650,427✔
7224
  pInfo->pHash = NULL;
1,650,802✔
7225
  taosMemoryFreeClear(pInfo->buf);
1,650,802✔
7226
}
1,650,802✔
7227

7228
void modeFunctionCleanupExt(SqlFunctionCtx* pCtx) {
774,813✔
7229
  if (pCtx == NULL || GET_RES_INFO(pCtx) == NULL || GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx)) == NULL) {
774,813✔
7230
    return;
67,811✔
7231
  }
7232
  modeFunctionCleanup(GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx)));
707,002✔
7233
}
7234

7235
static int32_t saveModeTupleData(SqlFunctionCtx* pCtx, char* data, SModeInfo* pInfo, STuplePos* pPos) {
105,137,098✔
7236
  if (IS_VAR_DATA_TYPE(pInfo->colType)) {
105,137,098✔
7237
    if (pInfo->colType == TSDB_DATA_TYPE_JSON) {
2,956,530✔
7238
      (void)memcpy(pInfo->buf, data, getJsonValueLen(data));
274,428✔
7239
    } else if (IS_STR_DATA_BLOB(pInfo->colType)) {
2,683,408✔
UNCOV
7240
      (void)memcpy(pInfo->buf, data, blobDataTLen(data));
×
7241
    } else {
7242
      (void)memcpy(pInfo->buf, data, varDataTLen(data));
2,683,790✔
7243
    }
7244
  } else {
7245
    (void)memcpy(pInfo->buf, data, pInfo->colBytes);
102,181,141✔
7246
  }
7247

7248
  return doSaveTupleData(&pCtx->saveHandle, pInfo->buf, pInfo->colBytes, NULL, pPos, pCtx->pStore);
105,140,109✔
7249
}
7250

7251
static int32_t doModeAdd(SModeInfo* pInfo, int32_t rowIndex, SqlFunctionCtx* pCtx, char* data) {
259,373,151✔
7252
  int32_t code = TSDB_CODE_SUCCESS;
259,373,151✔
7253
  int32_t hashKeyBytes;
7254
  if (IS_VAR_DATA_TYPE(pInfo->colType)) {
259,373,151✔
7255
    hashKeyBytes = calcStrBytesByType(pInfo->colType, data);
3,109,739✔
7256
  } else {
7257
    hashKeyBytes = pInfo->colBytes;
256,263,862✔
7258
  }
7259

7260
  SModeItem* pHashItem = (SModeItem*)taosHashGet(pInfo->pHash, data, hashKeyBytes);
259,374,438✔
7261
  if (pHashItem == NULL) {
259,371,427✔
7262
    int32_t   size = sizeof(SModeItem);
105,137,098✔
7263
    SModeItem item = {0};
105,137,098✔
7264

7265
    item.count += 1;
105,137,098✔
7266
    code = saveModeTupleData(pCtx, data, pInfo, &item.dataPos);
105,137,098✔
7267
    if (code != TSDB_CODE_SUCCESS) {
105,138,627✔
7268
      return code;
×
7269
    }
7270

7271
    if (pCtx->subsidiaries.num > 0) {
105,138,627✔
7272
      code = saveTupleData(pCtx, rowIndex, pCtx->pSrcBlock, &item.tuplePos);
259,551✔
7273
      if (code != TSDB_CODE_SUCCESS) {
259,551✔
7274
        return code;
×
7275
      }
7276
    }
7277

7278
    code = taosHashPut(pInfo->pHash, data, hashKeyBytes, &item, sizeof(SModeItem));
105,138,627✔
7279
    if (code != TSDB_CODE_SUCCESS) {
105,139,687✔
7280
      return code;
×
7281
    }
7282
  } else {
7283
    pHashItem->count += 1;
154,234,329✔
7284
    if (pCtx->subsidiaries.num > 0) {
154,234,329✔
7285
      code = updateTupleData(pCtx, rowIndex, pCtx->pSrcBlock, &pHashItem->tuplePos);
3,294,139✔
7286
      if (code != TSDB_CODE_SUCCESS) {
3,294,139✔
7287
        return code;
×
7288
      }
7289
    }
7290
  }
7291

7292
  return code;
259,266,736✔
7293
}
7294

7295
int32_t modeFunction(SqlFunctionCtx* pCtx) {
1,932,690✔
7296
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
1,932,690✔
7297
  SModeInfo*           pInfo = GET_ROWCELL_INTERBUF(pResInfo);
1,932,690✔
7298

7299
  SInputColumnInfoData* pInput = &pCtx->input;
1,932,160✔
7300

7301
  SColumnInfoData* pInputCol = pInput->pData[0];
1,932,690✔
7302
  SColumnInfoData* pOutput = (SColumnInfoData*)pCtx->pOutput;
1,932,690✔
7303

7304
  int32_t numOfElems = 0;
1,932,690✔
7305
  int32_t startOffset = pCtx->offset;
1,932,690✔
7306
  for (int32_t i = pInput->startRowIndex; i < pInput->numOfRows + pInput->startRowIndex; ++i) {
317,004,591✔
7307
    if (colDataIsNull_s(pInputCol, i)) {
630,156,619✔
7308
      continue;
55,710,616✔
7309
    }
7310
    numOfElems++;
259,372,206✔
7311

7312
    char*   data = colDataGetData(pInputCol, i);
259,372,206✔
7313
    int32_t code = doModeAdd(pInfo, i, pCtx, data);
259,373,533✔
7314
    if (code != TSDB_CODE_SUCCESS) {
259,372,736✔
7315
      modeFunctionCleanup(pInfo);
11,451✔
7316
      return code;
×
7317
    }
7318
  }
7319

7320
  if (numOfElems == 0 && pCtx->subsidiaries.num > 0 && !pInfo->nullTupleSaved) {
1,932,690✔
7321
    int32_t code = saveTupleData(pCtx, pInput->startRowIndex, pCtx->pSrcBlock, &pInfo->nullTuplePos);
4,450✔
7322
    if (code != TSDB_CODE_SUCCESS) {
4,450✔
7323
      modeFunctionCleanup(pInfo);
×
7324
      return code;
×
7325
    }
7326
    pInfo->nullTupleSaved = true;
4,450✔
7327
  }
7328

7329
  SET_VAL(pResInfo, numOfElems, 1);
1,932,690✔
7330

7331
  return TSDB_CODE_SUCCESS;
1,932,690✔
7332
}
7333

7334
int32_t modeFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
944,330✔
7335
  int32_t              code = TSDB_CODE_SUCCESS;
944,330✔
7336
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
944,330✔
7337
  SModeInfo*           pInfo = GET_ROWCELL_INTERBUF(pResInfo);
943,800✔
7338
  int32_t              slotId = pCtx->pExpr->base.resSchema.slotId;
944,330✔
7339
  SColumnInfoData*     pCol = taosArrayGet(pBlock->pDataBlock, slotId);
944,330✔
7340
  int32_t              currentRow = pBlock->info.rows;
944,330✔
7341
  if (NULL == pCol) {
944,330✔
7342
    modeFunctionCleanup(pInfo);
×
7343
    return TSDB_CODE_OUT_OF_RANGE;
×
7344
  }
7345

7346
  STuplePos resDataPos, resTuplePos;
944,330✔
7347
  int32_t   maxCount = 0;
944,330✔
7348

7349
  void* pIter = taosHashIterate(pInfo->pHash, NULL);
944,330✔
7350
  while (pIter != NULL) {
106,084,439✔
7351
    SModeItem* pItem = (SModeItem*)pIter;
105,140,109✔
7352
    if (pItem->count >= maxCount) {
105,140,109✔
7353
      maxCount = pItem->count;
96,125,961✔
7354
      resDataPos = pItem->dataPos;
96,125,961✔
7355
      resTuplePos = pItem->tuplePos;
96,125,961✔
7356
    }
7357

7358
    pIter = taosHashIterate(pInfo->pHash, pIter);
105,140,109✔
7359
  }
7360

7361
  if (maxCount != 0) {
944,330✔
7362
    char* pData = NULL;
617,334✔
7363
    code = loadTupleData(pCtx, &resDataPos, &pData);
617,334✔
7364
    if (pData == NULL || TSDB_CODE_SUCCESS != code) {
617,334✔
7365
      code = terrno = TSDB_CODE_NOT_FOUND;
×
7366
      qError("Load tuple data failed since %s, groupId:%" PRIu64 ", ts:%" PRId64, terrstr(),
×
7367
             resDataPos.streamTupleKey.groupId, resDataPos.streamTupleKey.ts);
7368
      modeFunctionCleanup(pInfo);
×
7369
      return code;
×
7370
    }
7371

7372
    code = colDataSetVal(pCol, currentRow, pData, false);
617,334✔
7373
    if (TSDB_CODE_SUCCESS != code) {
617,334✔
7374
      modeFunctionCleanup(pInfo);
×
7375
      return code;
×
7376
    }
7377
    code = setSelectivityValue(pCtx, pBlock, &resTuplePos, currentRow);
617,334✔
7378
  } else {
7379
    colDataSetNULL(pCol, currentRow);
326,996✔
7380
    code = setSelectivityValue(pCtx, pBlock, &pInfo->nullTuplePos, currentRow);
326,996✔
7381
  }
7382

7383
  modeFunctionCleanup(pInfo);
944,330✔
7384

7385
  return code;
944,330✔
7386
}
7387

7388
bool getTwaFuncEnv(struct SFunctionNode* pFunc, SFuncExecEnv* pEnv) {
301,910✔
7389
  pEnv->calcMemSize = sizeof(STwaInfo);
301,910✔
7390
  return true;
301,910✔
7391
}
7392

7393
int32_t twaFunctionSetup(SqlFunctionCtx* pCtx, SResultRowEntryInfo* pResultInfo) {
7,626,687✔
7394
  if (pResultInfo->initialized) {
7,626,687✔
7395
    return TSDB_CODE_SUCCESS;
×
7396
  }
7397
  if (TSDB_CODE_SUCCESS != functionSetup(pCtx, pResultInfo)) {
7,626,687✔
7398
    return TSDB_CODE_FUNC_SETUP_ERROR;
×
7399
  }
7400

7401
  STwaInfo* pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
7,626,687✔
7402
  pInfo->numOfElems = 0;
7,626,687✔
7403
  pInfo->p.key = INT64_MIN;
7,626,687✔
7404
  pInfo->win = TSWINDOW_INITIALIZER;
7,626,687✔
7405
  return TSDB_CODE_SUCCESS;
7,626,687✔
7406
}
7407

7408
static double twa_get_area(SPoint1 s, SPoint1 e) {
188,219,044✔
7409
  if (e.key == INT64_MAX || s.key == INT64_MIN) {
188,219,044✔
7410
    return 0;
×
7411
  }
7412

7413
  if ((s.val >= 0 && e.val >= 0) || (s.val <= 0 && e.val <= 0)) {
188,229,754✔
7414
    return (s.val + e.val) * (e.key - s.key) / 2;
170,849,875✔
7415
  }
7416

7417
  double x = (s.key * e.val - e.key * s.val) / (e.val - s.val);
17,379,879✔
7418
  double val = (s.val * (x - s.key) + e.val * (e.key - x)) / 2;
17,379,879✔
7419
  return val;
17,379,879✔
7420
}
7421

7422
int32_t twaFunction(SqlFunctionCtx* pCtx) {
7,664,356✔
7423
  int32_t               code = TSDB_CODE_SUCCESS;
7,664,356✔
7424
  SInputColumnInfoData* pInput = &pCtx->input;
7,664,356✔
7425
  SColumnInfoData*      pInputCol = pInput->pData[0];
7,664,356✔
7426

7427
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
7,664,356✔
7428
  STwaInfo*            pInfo = GET_ROWCELL_INTERBUF(pResInfo);
7,664,356✔
7429
  SPoint1*             last = &pInfo->p;
7,664,356✔
7430

7431
  if (IS_NULL_TYPE(pInputCol->info.type)) {
7,664,356✔
7432
    pInfo->numOfElems = 0;
×
7433
    goto _twa_over;
×
7434
  }
7435

7436
  funcInputUpdate(pCtx);
7,664,356✔
7437
  SFuncInputRow row = {0};
7,663,915✔
7438
  bool          result = false;
7,663,915✔
7439
  if (pCtx->start.key != INT64_MIN && last->key == INT64_MIN) {
7,663,915✔
7440
    while (1) {
7441
      code = funcInputGetNextRow(pCtx, &row, &result);
5,315,693✔
7442
      if (TSDB_CODE_SUCCESS != code) {
5,315,693✔
7443
        return code;
×
7444
      }
7445
      if (!result) {
5,315,693✔
7446
        break;
756✔
7447
      }
7448
      if (row.isDataNull) {
5,314,937✔
7449
        continue;
756✔
7450
      }
7451

7452
      last->key = row.ts;
5,314,181✔
7453

7454
      GET_TYPED_DATA(last->val, double, pInputCol->info.type, row.pData, typeGetTypeModFromColInfo(&pInputCol->info));
5,314,181✔
7455

7456
      pInfo->dOutput += twa_get_area(pCtx->start, *last);
5,314,181✔
7457
      pInfo->win.skey = pCtx->start.key;
5,314,181✔
7458
      pInfo->numOfElems++;
5,314,181✔
7459
      break;
5,314,181✔
7460
    }
7461
  } else if (pInfo->p.key == INT64_MIN) {
2,348,978✔
7462
    while (1) {
7463
      code = funcInputGetNextRow(pCtx, &row, &result);
9,237,548✔
7464
      if (TSDB_CODE_SUCCESS != code) {
9,237,548✔
7465
        return code;
×
7466
      }
7467
      if (!result) {
9,237,548✔
7468
        break;
640,139✔
7469
      }
7470
      if (row.isDataNull) {
8,597,409✔
7471
        continue;
6,921,460✔
7472
      }
7473

7474
      last->key = row.ts;
1,675,949✔
7475

7476
      GET_TYPED_DATA(last->val, double, pInputCol->info.type, row.pData, typeGetTypeModFromColInfo(&pInputCol->info));
1,675,949✔
7477

7478
      pInfo->win.skey = last->key;
1,675,949✔
7479
      pInfo->numOfElems++;
1,675,949✔
7480
      break;
1,675,949✔
7481
    }
7482
  }
7483

7484
  SPoint1 st = {0};
7,663,915✔
7485

7486
  // calculate the value of
7487
  while (1) {
7488
    code = funcInputGetNextRow(pCtx, &row, &result);
185,309,400✔
7489
    if (TSDB_CODE_SUCCESS != code) {
185,321,307✔
7490
      return code;
×
7491
    }
7492
    if (!result) {
185,321,307✔
7493
      break;
7,664,356✔
7494
    }
7495
    if (row.isDataNull) {
177,656,951✔
7496
      continue;
55,566✔
7497
    }
7498
    pInfo->numOfElems++;
177,601,385✔
7499
    switch (pInputCol->info.type) {
177,601,826✔
7500
      case TSDB_DATA_TYPE_TINYINT: {
13,506,421✔
7501
        INIT_INTP_POINT(st, row.ts, *(int8_t*)row.pData);
13,506,421✔
7502
        break;
13,506,421✔
7503
      }
7504
      case TSDB_DATA_TYPE_SMALLINT: {
14,769,344✔
7505
        INIT_INTP_POINT(st, row.ts, *(int16_t*)row.pData);
14,769,344✔
7506
        break;
14,769,344✔
7507
      }
7508
      case TSDB_DATA_TYPE_INT: {
75,300,460✔
7509
        INIT_INTP_POINT(st, row.ts, *(int32_t*)row.pData);
75,300,460✔
7510
        break;
75,300,019✔
7511
      }
7512
      case TSDB_DATA_TYPE_BIGINT: {
13,774,098✔
7513
        INIT_INTP_POINT(st, row.ts, *(int64_t*)row.pData);
13,774,098✔
7514
        break;
13,774,098✔
7515
      }
7516
      case TSDB_DATA_TYPE_FLOAT: {
11,723,724✔
7517
        INIT_INTP_POINT(st, row.ts, *(float_t*)row.pData);
11,723,724✔
7518
        break;
11,723,724✔
7519
      }
7520
      case TSDB_DATA_TYPE_DOUBLE: {
13,666,628✔
7521
        INIT_INTP_POINT(st, row.ts, *(double*)row.pData);
13,666,628✔
7522
        break;
13,666,628✔
7523
      }
7524
      case TSDB_DATA_TYPE_UTINYINT: {
8,900,010✔
7525
        INIT_INTP_POINT(st, row.ts, *(uint8_t*)row.pData);
8,900,010✔
7526
        break;
8,899,128✔
7527
      }
7528
      case TSDB_DATA_TYPE_USMALLINT: {
8,915,445✔
7529
        INIT_INTP_POINT(st, row.ts, *(uint16_t*)row.pData);
8,915,445✔
7530
        break;
8,915,445✔
7531
      }
7532
      case TSDB_DATA_TYPE_UINT: {
8,988,544✔
7533
        INIT_INTP_POINT(st, row.ts, *(uint32_t*)row.pData);
8,988,544✔
7534
        break;
8,988,544✔
7535
      }
7536
      case TSDB_DATA_TYPE_UBIGINT: {
8,056,711✔
7537
        INIT_INTP_POINT(st, row.ts, *(uint64_t*)row.pData);
8,056,711✔
7538
        break;
8,056,711✔
7539
      }
7540
      default: {
×
7541
        return TSDB_CODE_FUNC_FUNTION_PARA_TYPE;
×
7542
      }
7543
    }
7544
    if (pInfo->p.key == st.key) {
177,600,062✔
7545
      return TSDB_CODE_FUNC_DUP_TIMESTAMP;
×
7546
    }
7547

7548
    pInfo->dOutput += twa_get_area(pInfo->p, st);
177,600,503✔
7549
    pInfo->p = st;
177,581,540✔
7550
  }
7551

7552
  // the last interpolated time window value
7553
  if (pCtx->end.key != INT64_MIN) {
7,664,356✔
7554
    pInfo->dOutput += twa_get_area(pInfo->p, pCtx->end);
5,317,149✔
7555
    pInfo->p = pCtx->end;
5,317,149✔
7556
    pInfo->numOfElems += 1;
5,317,149✔
7557
  }
7558

7559
  pInfo->win.ekey = pInfo->p.key;
7,664,356✔
7560

7561
_twa_over:
7,664,356✔
7562
  SET_VAL(pResInfo, 1, 1);
7,664,356✔
7563
  return TSDB_CODE_SUCCESS;
7,664,356✔
7564
}
7565

7566
/*
7567
 * To copy the input to interResBuf to avoid the input buffer space be over writen
7568
 * by next input data. The TWA function only applies to each table, so no merge procedure
7569
 * is required, we simply copy to the resut ot interResBuffer.
7570
 */
7571
// void twa_function_copy(SQLFunctionCtx *pCtx) {
7572
//   SResultRowEntryInfo *pResInfo = GET_RES_INFO(pCtx);
7573
//
7574
//   memcpy(GET_ROWCELL_INTERBUF(pResInfo), pCtx->pInput, (size_t)pCtx->inputBytes);
7575
//   pResInfo->hasResult = ((STwaInfo *)pCtx->pInput)->hasResult;
7576
// }
7577

7578
int32_t twaFinalize(struct SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
7,626,687✔
7579
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
7,626,687✔
7580

7581
  STwaInfo* pInfo = (STwaInfo*)GET_ROWCELL_INTERBUF(pResInfo);
7,626,687✔
7582
  if (pInfo->numOfElems == 0) {
7,626,687✔
7583
    pResInfo->numOfRes = 0;
635,360✔
7584
  } else {
7585
    if (pInfo->win.ekey == pInfo->win.skey) {
6,991,327✔
7586
      pInfo->dTwaRes = pInfo->p.val;
835,975✔
7587
    } else if (pInfo->win.ekey == INT64_MAX || pInfo->win.skey == INT64_MIN) {  // no data in timewindow
6,155,352✔
7588
      pInfo->dTwaRes = 0;
756✔
7589
    } else {
7590
      pInfo->dTwaRes = pInfo->dOutput / (pInfo->win.ekey - pInfo->win.skey);
6,154,596✔
7591
    }
7592

7593
    pResInfo->numOfRes = 1;
6,991,327✔
7594
  }
7595

7596
  return functionFinalize(pCtx, pBlock);
7,626,687✔
7597
}
7598

7599
int32_t blockDistSetup(SqlFunctionCtx* pCtx, SResultRowEntryInfo* pResultInfo) {
2,881✔
7600
  if (pResultInfo->initialized) {
2,881✔
7601
    return TSDB_CODE_SUCCESS;
×
7602
  }
7603
  if (TSDB_CODE_SUCCESS != functionSetup(pCtx, pResultInfo)) {
2,881✔
7604
    return TSDB_CODE_FUNC_SETUP_ERROR;
×
7605
  }
7606

7607
  STableBlockDistInfo* pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
2,881✔
7608
  pInfo->minRows = INT32_MAX;
2,881✔
7609
  return TSDB_CODE_SUCCESS;
2,881✔
7610
}
7611

7612
int32_t blockDistFunction(SqlFunctionCtx* pCtx) {
5,515✔
7613
  const int32_t BLOCK_DIST_RESULT_ROWS = 25;
5,515✔
7614

7615
  SInputColumnInfoData* pInput = &pCtx->input;
5,515✔
7616
  SColumnInfoData*      pInputCol = pInput->pData[0];
5,515✔
7617
  SResultRowEntryInfo*  pResInfo = GET_RES_INFO(pCtx);
5,515✔
7618
  STableBlockDistInfo*  pDistInfo = GET_ROWCELL_INTERBUF(pResInfo);
5,515✔
7619

7620
  STableBlockDistInfo p1 = {0};
5,515✔
7621
  if (tDeserializeBlockDistInfo(varDataVal(pInputCol->pData), varDataLen(pInputCol->pData), &p1) < 0) {
5,515✔
7622
    qError("failed to deserialize block dist info");
×
7623
    return TSDB_CODE_FAILED;
×
7624
  }
7625

7626
  pDistInfo->numOfBlocks += p1.numOfBlocks;
5,515✔
7627
  pDistInfo->numOfTables += p1.numOfTables;
5,515✔
7628
  pDistInfo->numOfInmemRows += p1.numOfInmemRows;
5,515✔
7629
  pDistInfo->numOfSttRows += p1.numOfSttRows;
5,515✔
7630
  pDistInfo->totalSize += p1.totalSize;
5,515✔
7631
  pDistInfo->totalRows += p1.totalRows;
5,515✔
7632
  pDistInfo->numOfFiles += p1.numOfFiles;
5,515✔
7633

7634
  pDistInfo->defMinRows = p1.defMinRows;
5,515✔
7635
  pDistInfo->defMaxRows = p1.defMaxRows;
5,515✔
7636
  pDistInfo->rowSize = p1.rowSize;
5,515✔
7637

7638
  if (pDistInfo->minRows > p1.minRows) {
5,515✔
7639
    pDistInfo->minRows = p1.minRows;
1,295✔
7640
  }
7641
  if (pDistInfo->maxRows < p1.maxRows) {
5,515✔
7642
    pDistInfo->maxRows = p1.maxRows;
1,295✔
7643
  }
7644
  pDistInfo->numOfVgroups += (p1.numOfTables != 0 ? 1 : 0);
5,515✔
7645
  for (int32_t i = 0; i < tListLen(pDistInfo->blockRowsHisto); ++i) {
115,815✔
7646
    pDistInfo->blockRowsHisto[i] += p1.blockRowsHisto[i];
110,300✔
7647
  }
7648

7649
  pResInfo->numOfRes = BLOCK_DIST_RESULT_ROWS;  // default output rows
5,515✔
7650
  return TSDB_CODE_SUCCESS;
5,515✔
7651
}
7652

7653
int32_t tSerializeBlockDistInfo(void* buf, int32_t bufLen, const STableBlockDistInfo* pInfo) {
11,030✔
7654
  SEncoder encoder = {0};
11,030✔
7655
  int32_t  code = 0;
11,030✔
7656
  int32_t  lino;
7657
  int32_t  tlen;
7658
  tEncoderInit(&encoder, buf, bufLen);
11,030✔
7659

7660
  TAOS_CHECK_EXIT(tStartEncode(&encoder));
11,030✔
7661
  TAOS_CHECK_EXIT(tEncodeU32(&encoder, pInfo->rowSize));
22,043✔
7662

7663
  TAOS_CHECK_EXIT(tEncodeU16(&encoder, pInfo->numOfFiles));
22,026✔
7664
  TAOS_CHECK_EXIT(tEncodeU32(&encoder, pInfo->numOfBlocks));
22,026✔
7665
  TAOS_CHECK_EXIT(tEncodeU32(&encoder, pInfo->numOfTables));
22,009✔
7666

7667
  TAOS_CHECK_EXIT(tEncodeU64(&encoder, pInfo->totalSize));
22,009✔
7668
  TAOS_CHECK_EXIT(tEncodeU64(&encoder, pInfo->totalRows));
22,009✔
7669
  TAOS_CHECK_EXIT(tEncodeI32(&encoder, pInfo->maxRows));
22,026✔
7670
  TAOS_CHECK_EXIT(tEncodeI32(&encoder, pInfo->minRows));
22,043✔
7671
  TAOS_CHECK_EXIT(tEncodeI32(&encoder, pInfo->defMaxRows));
22,026✔
7672
  TAOS_CHECK_EXIT(tEncodeI32(&encoder, pInfo->defMinRows));
22,043✔
7673
  TAOS_CHECK_EXIT(tEncodeU32(&encoder, pInfo->numOfInmemRows));
22,060✔
7674
  TAOS_CHECK_EXIT(tEncodeU32(&encoder, pInfo->numOfSttRows));
22,043✔
7675
  TAOS_CHECK_EXIT(tEncodeU32(&encoder, pInfo->numOfVgroups));
22,026✔
7676

7677
  for (int32_t i = 0; i < tListLen(pInfo->blockRowsHisto); ++i) {
231,239✔
7678
    TAOS_CHECK_EXIT(tEncodeI32(&encoder, pInfo->blockRowsHisto[i]));
440,486✔
7679
  }
7680

7681
  tEndEncode(&encoder);
10,979✔
7682

7683
_exit:
11,030✔
7684
  if (code) {
11,030✔
7685
    tlen = code;
×
7686
  } else {
7687
    tlen = encoder.pos;
11,030✔
7688
  }
7689
  tEncoderClear(&encoder);
11,030✔
7690
  return tlen;
11,030✔
7691
}
7692

7693
int32_t tDeserializeBlockDistInfo(void* buf, int32_t bufLen, STableBlockDistInfo* pInfo) {
5,515✔
7694
  SDecoder decoder = {0};
5,515✔
7695
  int32_t  code = 0;
5,515✔
7696
  int32_t  lino;
7697
  tDecoderInit(&decoder, buf, bufLen);
5,515✔
7698

7699
  TAOS_CHECK_EXIT(tStartDecode(&decoder));
5,515✔
7700
  TAOS_CHECK_EXIT(tDecodeU32(&decoder, &pInfo->rowSize));
11,030✔
7701

7702
  TAOS_CHECK_EXIT(tDecodeU16(&decoder, &pInfo->numOfFiles));
11,030✔
7703
  TAOS_CHECK_EXIT(tDecodeU32(&decoder, &pInfo->numOfBlocks));
11,030✔
7704
  TAOS_CHECK_EXIT(tDecodeU32(&decoder, &pInfo->numOfTables));
11,030✔
7705

7706
  TAOS_CHECK_EXIT(tDecodeU64(&decoder, &pInfo->totalSize));
11,030✔
7707
  TAOS_CHECK_EXIT(tDecodeU64(&decoder, &pInfo->totalRows));
11,030✔
7708
  TAOS_CHECK_EXIT(tDecodeI32(&decoder, &pInfo->maxRows));
11,030✔
7709
  TAOS_CHECK_EXIT(tDecodeI32(&decoder, &pInfo->minRows));
11,030✔
7710
  TAOS_CHECK_EXIT(tDecodeI32(&decoder, &pInfo->defMaxRows));
11,030✔
7711
  TAOS_CHECK_EXIT(tDecodeI32(&decoder, &pInfo->defMinRows));
11,030✔
7712
  TAOS_CHECK_EXIT(tDecodeU32(&decoder, &pInfo->numOfInmemRows));
11,030✔
7713
  TAOS_CHECK_EXIT(tDecodeU32(&decoder, &pInfo->numOfSttRows));
11,030✔
7714
  TAOS_CHECK_EXIT(tDecodeU32(&decoder, &pInfo->numOfVgroups));
11,030✔
7715

7716
  for (int32_t i = 0; i < tListLen(pInfo->blockRowsHisto); ++i) {
115,815✔
7717
    TAOS_CHECK_EXIT(tDecodeI32(&decoder, &pInfo->blockRowsHisto[i]));
220,600✔
7718
  }
7719

7720
_exit:
5,515✔
7721
  tDecoderClear(&decoder);
5,515✔
7722
  return code;
5,515✔
7723
}
7724

7725
int32_t blockDistFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
2,881✔
7726
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
2,881✔
7727
  STableBlockDistInfo* pData = GET_ROWCELL_INTERBUF(pResInfo);
2,881✔
7728

7729
  SColumnInfoData* pColInfo = taosArrayGet(pBlock->pDataBlock, 0);
2,881✔
7730
  if (NULL == pColInfo) {
2,881✔
7731
    return TSDB_CODE_OUT_OF_RANGE;
×
7732
  }
7733

7734
  if (pData->totalRows == 0) {
2,881✔
7735
    pData->minRows = 0;
1,586✔
7736
  }
7737

7738
  int32_t row = 0;
2,881✔
7739
  char    st[256] = {0};
2,881✔
7740
  double  averageSize = 0;
2,881✔
7741
  if (pData->numOfBlocks != 0) {
2,881✔
7742
    averageSize = ((double)pData->totalSize) / pData->numOfBlocks;
1,295✔
7743
  }
7744
  uint64_t totalRawSize = pData->totalRows * pData->rowSize;
2,881✔
7745
  double   compRatio = 0;
2,881✔
7746
  if (totalRawSize != 0) {
2,881✔
7747
    compRatio = pData->totalSize * 100 / (double)totalRawSize;
1,295✔
7748
  }
7749

7750
  int32_t len = snprintf(varDataVal(st), sizeof(st) - VARSTR_HEADER_SIZE,
2,881✔
7751
                         "Total_Blocks=[%d] Total_Size=[%.2f KiB] Average_size=[%.2f KiB] Compression_Ratio=[%.2f %c]",
7752
                         pData->numOfBlocks, pData->totalSize / 1024.0, averageSize / 1024.0, compRatio, '%');
2,881✔
7753

7754
  varDataSetLen(st, len);
2,881✔
7755
  int32_t code = colDataSetVal(pColInfo, row++, st, false);
2,881✔
7756
  if (TSDB_CODE_SUCCESS != code) {
2,881✔
7757
    return code;
×
7758
  }
7759

7760
  int64_t avgRows = 0;
2,881✔
7761
  if (pData->numOfBlocks > 0) {
2,881✔
7762
    avgRows = pData->totalRows / pData->numOfBlocks;
1,295✔
7763
  }
7764

7765
  len = snprintf(varDataVal(st), sizeof(st) - VARSTR_HEADER_SIZE,
2,881✔
7766
                 "Block_Rows=[%" PRId64 "] MinRows=[%d] MaxRows=[%d] AvgRows=[%" PRId64 "]", pData->totalRows,
7767
                 pData->minRows, pData->maxRows, avgRows);
7768
  varDataSetLen(st, len);
2,881✔
7769
  code = colDataSetVal(pColInfo, row++, st, false);
2,881✔
7770
  if (TSDB_CODE_SUCCESS != code) {
2,881✔
7771
    return code;
×
7772
  }
7773

7774
  len = snprintf(varDataVal(st), sizeof(st) - VARSTR_HEADER_SIZE, "Inmem_Rows=[%u] Stt_Rows=[%u] ",
2,881✔
7775
                 pData->numOfInmemRows, pData->numOfSttRows);
7776
  varDataSetLen(st, len);
2,881✔
7777
  code = colDataSetVal(pColInfo, row++, st, false);
2,881✔
7778
  if (TSDB_CODE_SUCCESS != code) {
2,881✔
7779
    return code;
×
7780
  }
7781

7782
  len = snprintf(varDataVal(st), sizeof(st) - VARSTR_HEADER_SIZE,
5,762✔
7783
                 "Total_Tables=[%d] Total_Filesets=[%d] Total_Vgroups=[%d]", pData->numOfTables, pData->numOfFiles,
2,881✔
7784
                 pData->numOfVgroups);
7785

7786
  varDataSetLen(st, len);
2,881✔
7787
  code = colDataSetVal(pColInfo, row++, st, false);
2,881✔
7788
  if (TSDB_CODE_SUCCESS != code) {
2,881✔
7789
    return code;
×
7790
  }
7791

7792
  len = snprintf(varDataVal(st), sizeof(st) - VARSTR_HEADER_SIZE,
2,881✔
7793
                 "--------------------------------------------------------------------------------");
7794
  varDataSetLen(st, len);
2,881✔
7795
  code = colDataSetVal(pColInfo, row++, st, false);
2,881✔
7796
  if (TSDB_CODE_SUCCESS != code) {
2,881✔
7797
    return code;
×
7798
  }
7799

7800
  int32_t maxVal = 0;
2,881✔
7801
  int32_t minVal = INT32_MAX;
2,881✔
7802
  for (int32_t i = 0; i < tListLen(pData->blockRowsHisto); ++i) {
60,501✔
7803
    if (maxVal < pData->blockRowsHisto[i]) {
57,620✔
7804
      maxVal = pData->blockRowsHisto[i];
1,860✔
7805
    }
7806

7807
    if (minVal > pData->blockRowsHisto[i]) {
57,620✔
7808
      minVal = pData->blockRowsHisto[i];
3,611✔
7809
    }
7810
  }
7811

7812
  // maximum number of step is 80
7813
  double factor = pData->numOfBlocks / 80.0;
2,881✔
7814

7815
  int32_t numOfBuckets = sizeof(pData->blockRowsHisto) / sizeof(pData->blockRowsHisto[0]);
2,881✔
7816
  int32_t bucketRange = ceil(((double)(pData->defMaxRows - pData->defMinRows)) / numOfBuckets);
2,881✔
7817

7818
  for (int32_t i = 0; i < tListLen(pData->blockRowsHisto); ++i) {
60,501✔
7819
    len =
7820
        snprintf(varDataVal(st), sizeof(st) - VARSTR_HEADER_SIZE, "%04d |", pData->defMinRows + bucketRange * (i + 1));
57,620✔
7821

7822
    int32_t num = 0;
57,620✔
7823
    if (pData->blockRowsHisto[i] > 0) {
57,620✔
7824
      num = (pData->blockRowsHisto[i]) / factor;
2,990✔
7825
    }
7826

7827
    for (int32_t j = 0; j < num; ++j) {
160,655✔
7828
      int32_t x = snprintf(varDataVal(st) + len, sizeof(st) - VARSTR_HEADER_SIZE - len, "%c", '|');
103,035✔
7829
      len += x;
103,035✔
7830
    }
7831

7832
    if (pData->blockRowsHisto[i] > 0) {
57,620✔
7833
      double v = pData->blockRowsHisto[i] * 100.0 / pData->numOfBlocks;
2,990✔
7834
      len += snprintf(varDataVal(st) + len, sizeof(st) - VARSTR_HEADER_SIZE - len, "  %d (%.2f%c)",
2,990✔
7835
                      pData->blockRowsHisto[i], v, '%');
7836
    }
7837

7838
    varDataSetLen(st, len);
57,620✔
7839
    code = colDataSetVal(pColInfo, row++, st, false);
57,620✔
7840
    if (TSDB_CODE_SUCCESS != code) {
57,620✔
7841
      return code;
×
7842
    }
7843
  }
7844

7845
  return TSDB_CODE_SUCCESS;
2,881✔
7846
}
7847
int32_t blockDBUsageSetup(SqlFunctionCtx* pCtx, SResultRowEntryInfo* pResultInfo) {
358✔
7848
  if (pResultInfo->initialized) {
358✔
7849
    return TSDB_CODE_SUCCESS;
×
7850
  }
7851
  if (TSDB_CODE_SUCCESS != functionSetup(pCtx, pResultInfo)) {
358✔
7852
    return TSDB_CODE_FUNC_SETUP_ERROR;
×
7853
  }
7854

7855
  SDBBlockUsageInfo* pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
358✔
7856
  return TSDB_CODE_SUCCESS;
358✔
7857
}
7858
int32_t blockDBUsageFunction(SqlFunctionCtx* pCtx) {
716✔
7859
  const int32_t BLOCK_DISK_USAGE_RESULT_ROWS = 2;
716✔
7860

7861
  SInputColumnInfoData* pInput = &pCtx->input;
716✔
7862
  SColumnInfoData*      pInputCol = pInput->pData[0];
716✔
7863
  SResultRowEntryInfo*  pResInfo = GET_RES_INFO(pCtx);
716✔
7864
  SDBBlockUsageInfo*    pDistInfo = GET_ROWCELL_INTERBUF(pResInfo);
716✔
7865

7866
  SDBBlockUsageInfo p1 = {0};
716✔
7867
  if (tDeserializeBlockDbUsage(varDataVal(pInputCol->pData), varDataLen(pInputCol->pData), &p1) < 0) {
716✔
7868
    qError("failed to deserialize block dist info");
×
7869
    return TSDB_CODE_FAILED;
×
7870
  }
7871

7872
  pDistInfo->dataInDiskSize += p1.dataInDiskSize;
716✔
7873
  pDistInfo->walInDiskSize += p1.walInDiskSize;
716✔
7874
  pDistInfo->rawDataSize += p1.rawDataSize;
716✔
7875
  pResInfo->numOfRes = BLOCK_DISK_USAGE_RESULT_ROWS;  // default output rows
716✔
7876
  return TSDB_CODE_SUCCESS;
716✔
7877
}
7878

7879
int32_t tSerializeBlockDbUsage(void* buf, int32_t bufLen, const SDBBlockUsageInfo* pInfo) {
1,432✔
7880
  SEncoder encoder = {0};
1,432✔
7881
  int32_t  code = 0;
1,432✔
7882
  int32_t  lino;
7883
  int32_t  tlen;
7884
  tEncoderInit(&encoder, buf, bufLen);
1,432✔
7885

7886
  TAOS_CHECK_EXIT(tStartEncode(&encoder));
1,432✔
7887

7888
  TAOS_CHECK_EXIT(tEncodeU64(&encoder, pInfo->dataInDiskSize));
2,864✔
7889
  TAOS_CHECK_EXIT(tEncodeU64(&encoder, pInfo->walInDiskSize));
2,864✔
7890
  TAOS_CHECK_EXIT(tEncodeU64(&encoder, pInfo->rawDataSize));
2,864✔
7891

7892
  tEndEncode(&encoder);
1,432✔
7893

7894
_exit:
1,432✔
7895
  if (code) {
1,432✔
7896
    tlen = code;
×
7897
  } else {
7898
    tlen = encoder.pos;
1,432✔
7899
  }
7900
  tEncoderClear(&encoder);
1,432✔
7901
  return tlen;
1,432✔
7902
}
7903
int32_t tDeserializeBlockDbUsage(void* buf, int32_t bufLen, SDBBlockUsageInfo* pInfo) {
716✔
7904
  SDecoder decoder = {0};
716✔
7905
  int32_t  code = 0;
716✔
7906
  int32_t  lino;
7907
  tDecoderInit(&decoder, buf, bufLen);
716✔
7908

7909
  TAOS_CHECK_EXIT(tStartDecode(&decoder));
716✔
7910
  TAOS_CHECK_EXIT(tDecodeU64(&decoder, &pInfo->dataInDiskSize));
1,432✔
7911
  TAOS_CHECK_EXIT(tDecodeU64(&decoder, &pInfo->walInDiskSize));
1,432✔
7912
  TAOS_CHECK_EXIT(tDecodeU64(&decoder, &pInfo->rawDataSize));
1,432✔
7913

7914
_exit:
716✔
7915
  tDecoderClear(&decoder);
716✔
7916
  return code;
716✔
7917
}
7918
int32_t blockDBUsageFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
358✔
7919
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
358✔
7920
  SDBBlockUsageInfo*   pData = GET_ROWCELL_INTERBUF(pResInfo);
358✔
7921

7922
  SColumnInfoData* pColInfo = taosArrayGet(pBlock->pDataBlock, 0);
358✔
7923
  if (NULL == pColInfo) {
358✔
7924
    return TSDB_CODE_OUT_OF_RANGE;
×
7925
  }
7926
  int32_t len = 0;
358✔
7927
  int32_t row = 0;
358✔
7928
  char    st[256] = {0};
358✔
7929

7930
  uint64_t totalDiskSize = pData->dataInDiskSize;
358✔
7931
  uint64_t rawDataSize = pData->rawDataSize;
358✔
7932
  double   compressRatio = 0;
358✔
7933
  if (rawDataSize != 0) {
358✔
7934
    compressRatio = totalDiskSize * 100 / (double)rawDataSize;
185✔
7935
    len = tsnprintf(varDataVal(st), sizeof(st) - VARSTR_HEADER_SIZE, "Compress_ratio=[%.2f%]", compressRatio);
185✔
7936
  } else {
7937
    len = tsnprintf(varDataVal(st), sizeof(st) - VARSTR_HEADER_SIZE, "Compress_ratio=[NULL]");
173✔
7938
  }
7939

7940
  varDataSetLen(st, len);
358✔
7941
  int32_t code = colDataSetVal(pColInfo, row++, st, false);
358✔
7942
  if (TSDB_CODE_SUCCESS != code) {
358✔
7943
    return code;
×
7944
  }
7945

7946
  len =
7947
      snprintf(varDataVal(st), sizeof(st) - VARSTR_HEADER_SIZE, "Disk_occupied=[%" PRId64 "k]", pData->dataInDiskSize);
358✔
7948
  varDataSetLen(st, len);
358✔
7949
  code = colDataSetVal(pColInfo, row++, st, false);
358✔
7950
  if (TSDB_CODE_SUCCESS != code) {
358✔
7951
    return code;
×
7952
  }
7953
  return code;
358✔
7954
}
7955

7956
bool getDerivativeFuncEnv(struct SFunctionNode* pFunc, SFuncExecEnv* pEnv) {
216,865✔
7957
  pEnv->calcMemSize = sizeof(SDerivInfo);
216,865✔
7958
  return true;
216,865✔
7959
}
7960

7961
int32_t derivativeFuncSetup(SqlFunctionCtx* pCtx, SResultRowEntryInfo* pResInfo) {
490,712✔
7962
  if (pResInfo->initialized) {
490,712✔
7963
    return TSDB_CODE_SUCCESS;
241,273✔
7964
  }
7965
  if (TSDB_CODE_SUCCESS != functionSetup(pCtx, pResInfo)) {
249,439✔
7966
    return TSDB_CODE_FUNC_SETUP_ERROR;
×
7967
  }
7968

7969
  SDerivInfo* pDerivInfo = GET_ROWCELL_INTERBUF(pResInfo);
249,439✔
7970

7971
  pDerivInfo->ignoreNegative = pCtx->param[2].param.i;
249,439✔
7972
  pDerivInfo->prevTs = -1;
249,439✔
7973
  pDerivInfo->tsWindow = pCtx->param[1].param.i;
249,439✔
7974
  pDerivInfo->valueSet = false;
249,439✔
7975
  return TSDB_CODE_SUCCESS;
249,439✔
7976
}
7977

7978
int32_t derivativeFunction(SqlFunctionCtx* pCtx) { return TSDB_CODE_SUCCESS; }
273,847✔
7979

7980
static int32_t DoDerivativeFunction(SqlFunctionCtx* pCtx) {
273,847✔
7981
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
273,847✔
7982
  SDerivInfo*          pDerivInfo = GET_ROWCELL_INTERBUF(pResInfo);
273,847✔
7983

7984
  SInputColumnInfoData* pInput = &pCtx->input;
273,847✔
7985
  SColumnInfoData*      pInputCol = pInput->pData[0];
273,847✔
7986

7987
  int32_t          numOfElems = 0;
273,847✔
7988
  SColumnInfoData* pOutput = (SColumnInfoData*)pCtx->pOutput;
273,847✔
7989
  SColumnInfoData* pTsOutput = pCtx->pTsOutput;
273,847✔
7990
  int32_t          code = TSDB_CODE_SUCCESS;
273,847✔
7991

7992
  funcInputUpdate(pCtx);
273,847✔
7993

7994
  double v = 0;
273,847✔
7995
  if (pCtx->order == TSDB_ORDER_ASC) {
273,847✔
7996
    SFuncInputRow row = {0};
269,649✔
7997
    bool          result = false;
269,649✔
7998
    while (1) {
125,433,224✔
7999
      code = funcInputGetNextRow(pCtx, &row, &result);
125,702,873✔
8000
      if (TSDB_CODE_SUCCESS != code) {
125,702,873✔
8001
        return code;
×
8002
      }
8003
      if (!result) {
125,702,873✔
8004
        break;
269,649✔
8005
      }
8006
      if (row.isDataNull) {
125,433,224✔
8007
        continue;
3,283,536✔
8008
      }
8009

8010
      char* d = row.pData;
122,149,688✔
8011
      GET_TYPED_DATA(v, double, pInputCol->info.type, d, typeGetTypeModFromColInfo(&pInputCol->info));
122,149,688✔
8012

8013
      int32_t pos = pCtx->offset + numOfElems;
122,149,688✔
8014
      if (!pDerivInfo->valueSet) {  // initial value is not set yet
122,149,688✔
8015
        pDerivInfo->valueSet = true;
211,582✔
8016
      } else {
8017
        if (row.ts == pDerivInfo->prevTs) {
121,938,106✔
8018
          return TSDB_CODE_FUNC_DUP_TIMESTAMP;
×
8019
        }
8020
        double r = ((v - pDerivInfo->prevValue) * pDerivInfo->tsWindow) / (row.ts - pDerivInfo->prevTs);
121,938,106✔
8021
        if (pDerivInfo->ignoreNegative && r < 0) {
121,938,106✔
8022
        } else {
8023
          if (isinf(r) || isnan(r)) {
111,360,776✔
8024
            colDataSetNULL(pOutput, pos);
×
8025
          } else {
8026
            code = colDataSetVal(pOutput, pos, (const char*)&r, false);
111,360,776✔
8027
            if (code != TSDB_CODE_SUCCESS) {
111,360,776✔
8028
              return code;
×
8029
            }
8030
          }
8031

8032
          if (pTsOutput != NULL) {
111,360,776✔
8033
            colDataSetInt64(pTsOutput, pos, &row.ts);
×
8034
          }
8035

8036
          // handle selectivity
8037
          if (pCtx->subsidiaries.num > 0) {
111,360,776✔
8038
            code = appendSelectivityCols(pCtx, row.block, row.rowIndex, pos);
2,043,756✔
8039
            if (code != TSDB_CODE_SUCCESS) {
2,043,756✔
8040
              return code;
×
8041
            }
8042
          }
8043

8044
          numOfElems++;
111,360,776✔
8045
        }
8046
      }
8047

8048
      pDerivInfo->prevValue = v;
122,149,688✔
8049
      pDerivInfo->prevTs = row.ts;
122,149,688✔
8050
    }
8051
  } else {
8052
    SFuncInputRow row = {0};
4,198✔
8053
    bool          result = false;
4,198✔
8054
    while (1) {
17,504✔
8055
      code = funcInputGetNextRow(pCtx, &row, &result);
21,702✔
8056
      if (TSDB_CODE_SUCCESS != code) {
21,702✔
8057
        return code;
×
8058
      }
8059
      if (!result) {
21,702✔
8060
        break;
4,198✔
8061
      }
8062
      if (row.isDataNull) {
17,504✔
8063
        continue;
12,244✔
8064
      }
8065

8066
      char* d = row.pData;
5,260✔
8067
      GET_TYPED_DATA(v, double, pInputCol->info.type, d, typeGetTypeModFromColInfo(&pInputCol->info));
5,260✔
8068

8069
      int32_t pos = pCtx->offset + numOfElems;
5,260✔
8070
      if (!pDerivInfo->valueSet) {  // initial value is not set yet
5,260✔
8071
        pDerivInfo->valueSet = true;
2,630✔
8072
      } else {
8073
        if (row.ts == pDerivInfo->prevTs) {
2,630✔
8074
          return TSDB_CODE_FUNC_DUP_TIMESTAMP;
×
8075
        }
8076
        double r = ((pDerivInfo->prevValue - v) * pDerivInfo->tsWindow) / (pDerivInfo->prevTs - row.ts);
2,630✔
8077
        if (pDerivInfo->ignoreNegative && r < 0) {
2,630✔
8078
        } else {
8079
          if (isinf(r) || isnan(r)) {
2,124✔
8080
            colDataSetNULL(pOutput, pos);
×
8081
          } else {
8082
            code = colDataSetVal(pOutput, pos, (const char*)&r, false);
2,124✔
8083
            if (code != TSDB_CODE_SUCCESS) {
2,124✔
8084
              return code;
×
8085
            }
8086
          }
8087

8088
          if (pTsOutput != NULL) {
2,124✔
8089
            colDataSetInt64(pTsOutput, pos, &pDerivInfo->prevTs);
×
8090
          }
8091

8092
          // handle selectivity
8093
          if (pCtx->subsidiaries.num > 0) {
2,124✔
8094
            code = appendSelectivityCols(pCtx, row.block, row.rowIndex, pos);
×
8095
            if (code != TSDB_CODE_SUCCESS) {
×
8096
              return code;
×
8097
            }
8098
          }
8099
          numOfElems++;
2,124✔
8100
        }
8101
      }
8102

8103
      pDerivInfo->prevValue = v;
5,260✔
8104
      pDerivInfo->prevTs = row.ts;
5,260✔
8105
    }
8106
  }
8107

8108
  pResInfo->numOfRes = numOfElems;
273,847✔
8109

8110
  return TSDB_CODE_SUCCESS;
273,847✔
8111
}
8112

8113
int32_t derivativeFunctionByRow(SArray* pCtxArray) {
273,847✔
8114
  for (int32_t i = 0; i < taosArrayGetSize(pCtxArray); ++i) {
547,694✔
8115
    SqlFunctionCtx* pCtx = *(SqlFunctionCtx**)taosArrayGet(pCtxArray, i);
273,847✔
8116
    int32_t         code = DoDerivativeFunction(pCtx);
273,847✔
8117
    if (code != TSDB_CODE_SUCCESS) {
273,847✔
8118
      return code;
×
8119
    }
8120
  }
8121
  return TSDB_CODE_SUCCESS;
273,847✔
8122
}
8123

8124
int32_t getIrateInfoSize(int32_t pkBytes) { return (int32_t)sizeof(SRateInfo) + 2 * pkBytes; }
251,493✔
8125

8126
bool getIrateFuncEnv(struct SFunctionNode* pFunc, SFuncExecEnv* pEnv) {
209,622✔
8127
  int32_t pkBytes = (pFunc->hasPk) ? pFunc->pkBytes : 0;
209,622✔
8128
  pEnv->calcMemSize = getIrateInfoSize(pkBytes);
209,622✔
8129
  return true;
209,622✔
8130
}
8131

8132
int32_t irateFuncSetup(SqlFunctionCtx* pCtx, SResultRowEntryInfo* pResInfo) {
1,635,554✔
8133
  if (pResInfo->initialized) {
1,635,554✔
8134
    return TSDB_CODE_SUCCESS;
×
8135
  }
8136
  if (TSDB_CODE_SUCCESS != functionSetup(pCtx, pResInfo)) {
1,635,554✔
8137
    return TSDB_CODE_FUNC_SETUP_ERROR;
×
8138
  }
8139

8140
  SRateInfo* pInfo = GET_ROWCELL_INTERBUF(pResInfo);
1,635,554✔
8141

8142
  pInfo->firstKey = INT64_MIN;
1,635,554✔
8143
  pInfo->lastKey = INT64_MIN;
1,635,554✔
8144
  pInfo->firstValue = (double)INT64_MIN;
1,635,554✔
8145
  pInfo->lastValue = (double)INT64_MIN;
1,635,554✔
8146

8147
  pInfo->hasResult = 0;
1,635,554✔
8148
  return TSDB_CODE_SUCCESS;
1,635,554✔
8149
}
8150

8151
static void doSaveRateInfo(SRateInfo* pRateInfo, bool isFirst, int64_t ts, char* pk, double v) {
303,865,207✔
8152
  if (isFirst) {
303,865,207✔
8153
    pRateInfo->firstValue = v;
151,481,725✔
8154
    pRateInfo->firstKey = ts;
151,481,725✔
8155
    if (pRateInfo->firstPk) {
151,481,725✔
8156
      int32_t pkBytes;
8157
      if (IS_VAR_DATA_TYPE(pRateInfo->pkType)) {
24,080✔
8158
        pkBytes = calcStrBytesByType(pRateInfo->pkType, pk);
5,504✔
8159
      } else {
8160
        pkBytes = pRateInfo->pkBytes;
18,576✔
8161
      }
8162
      (void)memcpy(pRateInfo->firstPk, pk, pkBytes);
24,080✔
8163
    }
8164
  } else {
8165
    pRateInfo->lastValue = v;
152,383,482✔
8166
    pRateInfo->lastKey = ts;
152,383,482✔
8167
    if (pRateInfo->lastPk) {
152,383,482✔
8168
      int32_t pkBytes;
8169
      if (IS_VAR_DATA_TYPE(pRateInfo->pkType)) {
35,776✔
8170
        pkBytes = calcStrBytesByType(pRateInfo->pkType, pk);
8,256✔
8171
      } else {
8172
        pkBytes = pRateInfo->pkBytes;
27,520✔
8173
      }
8174
      (void)memcpy(pRateInfo->lastPk, pk, pkBytes);
35,776✔
8175
    }
8176
  }
8177
}
303,865,207✔
8178

8179
static void initializeRateInfo(SqlFunctionCtx* pCtx, SRateInfo* pRateInfo, bool isMerge) {
1,811,284✔
8180
  if (pCtx->hasPrimaryKey) {
1,811,284✔
8181
    if (!isMerge) {
13,072✔
8182
      pRateInfo->pkType = pCtx->input.pPrimaryKey->info.type;
11,696✔
8183
      pRateInfo->pkBytes = pCtx->input.pPrimaryKey->info.bytes;
11,696✔
8184
      pRateInfo->firstPk = pRateInfo->pkData;
11,696✔
8185
      pRateInfo->lastPk = pRateInfo->pkData + pRateInfo->pkBytes;
11,696✔
8186
    } else {
8187
      pRateInfo->firstPk = pRateInfo->pkData;
1,376✔
8188
      pRateInfo->lastPk = pRateInfo->pkData + pRateInfo->pkBytes;
1,376✔
8189
    }
8190
  } else {
8191
    pRateInfo->firstPk = NULL;
1,798,212✔
8192
    pRateInfo->lastPk = NULL;
1,798,212✔
8193
  }
8194
}
1,811,284✔
8195

8196
int32_t irateFunction(SqlFunctionCtx* pCtx) {
1,749,648✔
8197
  int32_t              code = TSDB_CODE_SUCCESS;
1,749,648✔
8198
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
1,749,648✔
8199
  SRateInfo*           pRateInfo = GET_ROWCELL_INTERBUF(pResInfo);
1,749,648✔
8200

8201
  SInputColumnInfoData* pInput = &pCtx->input;
1,749,648✔
8202
  SColumnInfoData*      pInputCol = pInput->pData[0];
1,749,648✔
8203

8204
  SColumnInfoData* pOutput = (SColumnInfoData*)pCtx->pOutput;
1,749,648✔
8205

8206
  funcInputUpdate(pCtx);
1,749,648✔
8207

8208
  initializeRateInfo(pCtx, pRateInfo, false);
1,749,648✔
8209

8210
  int32_t       numOfElems = 0;
1,749,648✔
8211
  int32_t       type = pInputCol->info.type;
1,749,648✔
8212
  SFuncInputRow row = {0};
1,749,648✔
8213
  bool          result = false;
1,749,648✔
8214
  while (1) {
200,562,631✔
8215
    code = funcInputGetNextRow(pCtx, &row, &result);
202,312,279✔
8216
    if (TSDB_CODE_SUCCESS != code) {
202,312,279✔
8217
      return code;
×
8218
    }
8219
    if (!result) {
202,312,279✔
8220
      break;
1,749,648✔
8221
    }
8222
    if (row.isDataNull) {
200,562,631✔
8223
      continue;
7,412,223✔
8224
    }
8225

8226
    char*  data = row.pData;
193,150,408✔
8227
    double v = 0;
193,150,408✔
8228
    GET_TYPED_DATA(v, double, type, data, typeGetTypeModFromColInfo(&pInputCol->info));
193,150,408✔
8229

8230
    if (INT64_MIN == pRateInfo->lastKey) {
193,150,408✔
8231
      doSaveRateInfo(pRateInfo, false, row.ts, row.pPk, v);
905,293✔
8232
      pRateInfo->hasResult = 1;
905,293✔
8233
      continue;
905,293✔
8234
    }
8235

8236
    if (row.ts > pRateInfo->lastKey) {
192,245,115✔
8237
      if ((INT64_MIN == pRateInfo->firstKey) || pRateInfo->lastKey > pRateInfo->firstKey) {
151,445,523✔
8238
        doSaveRateInfo(pRateInfo, true, pRateInfo->lastKey, pRateInfo->lastPk, pRateInfo->lastValue);
151,445,523✔
8239
      }
8240
      doSaveRateInfo(pRateInfo, false, row.ts, row.pPk, v);
151,445,523✔
8241
      continue;
151,445,523✔
8242
    } else if (row.ts == pRateInfo->lastKey) {
40,799,592✔
8243
      return TSDB_CODE_FUNC_DUP_TIMESTAMP;
×
8244
    }
8245

8246
    if ((INT64_MIN == pRateInfo->firstKey) || row.ts > pRateInfo->firstKey) {
40,799,592✔
8247
      doSaveRateInfo(pRateInfo, true, row.ts, row.pPk, v);
×
8248
    } else if (row.ts == pRateInfo->firstKey) {
40,799,592✔
8249
      return TSDB_CODE_FUNC_DUP_TIMESTAMP;
×
8250
    }
8251
  }
8252

8253
  numOfElems++;
1,749,648✔
8254

8255
  SET_VAL(pResInfo, numOfElems, 1);
1,749,648✔
8256
  return TSDB_CODE_SUCCESS;
1,749,648✔
8257
}
8258

8259
static double doCalcRate(const SRateInfo* pRateInfo, double tickPerSec) {
1,604,736✔
8260
  if ((INT64_MIN == pRateInfo->lastKey) || (INT64_MIN == pRateInfo->firstKey) ||
1,604,736✔
8261
      (pRateInfo->firstKey >= pRateInfo->lastKey)) {
147,726✔
8262
    return 0.0;
1,457,010✔
8263
  }
8264

8265
  double diff = 0;
147,726✔
8266
  // If the previous value of the last is greater than the last value, only keep the last point instead of the delta
8267
  // value between two values.
8268
  diff = pRateInfo->lastValue;
147,726✔
8269
  if (diff >= pRateInfo->firstValue) {
147,726✔
8270
    diff -= pRateInfo->firstValue;
81,776✔
8271
  }
8272

8273
  int64_t duration = pRateInfo->lastKey - pRateInfo->firstKey;
147,726✔
8274
  if (duration == 0) {
147,726✔
8275
    return 0;
×
8276
  }
8277

8278
  return (duration > 0) ? ((double)diff) / (duration / tickPerSec) : 0.0;
147,726✔
8279
}
8280

8281
static void irateTransferInfoImpl(TSKEY inputKey, SRateInfo* pInput, SRateInfo* pOutput, bool isFirstKey) {
25,416✔
8282
  if (inputKey > pOutput->lastKey) {
25,416✔
8283
    doSaveRateInfo(pOutput, true, pOutput->lastKey, pOutput->lastPk, pOutput->lastValue);
16,576✔
8284
    if (isFirstKey) {
16,576✔
8285
      doSaveRateInfo(pOutput, false, pInput->firstKey, pInput->firstPk, pInput->firstValue);
7,846✔
8286
    } else {
8287
      doSaveRateInfo(pOutput, false, pInput->lastKey, pInput->lastPk, pInput->lastValue);
8,730✔
8288
    }
8289
  } else if ((inputKey < pOutput->lastKey) && (inputKey > pOutput->firstKey)) {
8,840✔
8290
    if (isFirstKey) {
3,536✔
8291
      doSaveRateInfo(pOutput, true, pInput->firstKey, pInput->firstPk, pInput->firstValue);
1,768✔
8292
    } else {
8293
      doSaveRateInfo(pOutput, true, pInput->lastKey, pInput->lastPk, pInput->lastValue);
1,768✔
8294
    }
8295
  } else {
8296
    // inputKey < pOutput->firstKey
8297
  }
8298
}
25,416✔
8299

8300
static void irateCopyInfo(SRateInfo* pInput, SRateInfo* pOutput) {
16,090✔
8301
  doSaveRateInfo(pOutput, true, pInput->firstKey, pInput->firstPk, pInput->firstValue);
16,090✔
8302
  doSaveRateInfo(pOutput, false, pInput->lastKey, pInput->lastPk, pInput->lastValue);
16,090✔
8303
}
16,090✔
8304

8305
static int32_t irateTransferInfo(SRateInfo* pInput, SRateInfo* pOutput) {
28,798✔
8306
  if ((pInput->firstKey != INT64_MIN &&
28,798✔
8307
       (pInput->firstKey == pOutput->firstKey || pInput->firstKey == pOutput->lastKey)) ||
26,104✔
8308
      (pInput->lastKey != INT64_MIN && (pInput->lastKey == pOutput->firstKey || pInput->lastKey == pOutput->lastKey))) {
28,798✔
8309
    return TSDB_CODE_FUNC_DUP_TIMESTAMP;
×
8310
  }
8311

8312
  if (pOutput->hasResult == 0) {
28,798✔
8313
    irateCopyInfo(pInput, pOutput);
16,090✔
8314
    pOutput->hasResult = pInput->hasResult;
16,090✔
8315
    return TSDB_CODE_SUCCESS;
16,090✔
8316
  }
8317

8318
  if (pInput->firstKey != INT64_MIN) {
12,708✔
8319
    irateTransferInfoImpl(pInput->firstKey, pInput, pOutput, true);
12,708✔
8320
  }
8321

8322
  if (pInput->lastKey != INT64_MIN) {
12,708✔
8323
    irateTransferInfoImpl(pInput->lastKey, pInput, pOutput, false);
12,708✔
8324
  }
8325

8326
  pOutput->hasResult = pInput->hasResult;
12,708✔
8327
  return TSDB_CODE_SUCCESS;
12,708✔
8328
}
8329

8330
int32_t irateFunctionMerge(SqlFunctionCtx* pCtx) {
30,818✔
8331
  SInputColumnInfoData* pInput = &pCtx->input;
30,818✔
8332
  SColumnInfoData*      pCol = pInput->pData[0];
30,818✔
8333
  if (pCol->info.type != TSDB_DATA_TYPE_BINARY) {
30,818✔
8334
    return TSDB_CODE_FUNC_FUNTION_PARA_TYPE;
×
8335
  }
8336

8337
  SRateInfo* pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
30,818✔
8338
  initializeRateInfo(pCtx, pInfo, true);
30,818✔
8339

8340
  int32_t start = pInput->startRowIndex;
30,818✔
8341
  for (int32_t i = start; i < start + pInput->numOfRows; ++i) {
61,636✔
8342
    char*      data = colDataGetData(pCol, i);
30,818✔
8343
    SRateInfo* pInputInfo = (SRateInfo*)varDataVal(data);
30,818✔
8344
    initializeRateInfo(pCtx, pInfo, true);
30,818✔
8345
    if (pInputInfo->hasResult) {
30,818✔
8346
      int32_t code = irateTransferInfo(pInputInfo, pInfo);
28,798✔
8347
      if (code != TSDB_CODE_SUCCESS) {
28,798✔
8348
        return code;
×
8349
      }
8350
    }
8351
  }
8352

8353
  if (pInfo->hasResult) {
30,818✔
8354
    GET_RES_INFO(pCtx)->numOfRes = 1;
28,798✔
8355
  }
8356

8357
  return TSDB_CODE_SUCCESS;
30,818✔
8358
}
8359

8360
int32_t iratePartialFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
30,818✔
8361
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
30,818✔
8362
  SRateInfo*           pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
30,818✔
8363
  int32_t              resultBytes = getIrateInfoSize(pInfo->pkBytes);
30,818✔
8364
  char*                res = taosMemoryCalloc(resultBytes + VARSTR_HEADER_SIZE, sizeof(char));
30,818✔
8365

8366
  if (NULL == res) {
30,818✔
8367
    return terrno;
×
8368
  }
8369
  (void)memcpy(varDataVal(res), pInfo, resultBytes);
30,818✔
8370
  varDataSetLen(res, resultBytes);
30,818✔
8371

8372
  int32_t          slotId = pCtx->pExpr->base.resSchema.slotId;
30,818✔
8373
  SColumnInfoData* pCol = taosArrayGet(pBlock->pDataBlock, slotId);
30,818✔
8374
  if (NULL == pCol) {
30,818✔
8375
    taosMemoryFree(res);
×
8376
    return TSDB_CODE_OUT_OF_RANGE;
×
8377
  }
8378

8379
  int32_t code = colDataSetVal(pCol, pBlock->info.rows, res, false);
30,818✔
8380

8381
  taosMemoryFree(res);
30,818✔
8382
  return code;
30,818✔
8383
}
8384

8385
int32_t irateFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
1,604,736✔
8386
  int32_t          slotId = pCtx->pExpr->base.resSchema.slotId;
1,604,736✔
8387
  SColumnInfoData* pCol = taosArrayGet(pBlock->pDataBlock, slotId);
1,604,736✔
8388
  if (NULL == pCol) {
1,604,736✔
8389
    return TSDB_CODE_OUT_OF_RANGE;
×
8390
  }
8391

8392
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
1,604,736✔
8393
  pResInfo->isNullRes = (pResInfo->numOfRes == 0) ? 1 : 0;
1,604,736✔
8394

8395
  SRateInfo* pInfo = GET_ROWCELL_INTERBUF(pResInfo);
1,604,736✔
8396
  double     result = doCalcRate(pInfo, (double)TSDB_TICK_PER_SECOND(pCtx->param[1].param.i));
1,604,736✔
8397
  int32_t    code = colDataSetVal(pCol, pBlock->info.rows, (const char*)&result, pResInfo->isNullRes);
1,604,736✔
8398

8399
  return code;
1,604,736✔
8400
}
8401

8402
int32_t groupConstValueFunction(SqlFunctionCtx* pCtx) {
2,147,483,647✔
8403
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
2,147,483,647✔
8404
  SGroupKeyInfo*       pInfo = GET_ROWCELL_INTERBUF(pResInfo);
2,147,483,647✔
8405
  bool                 isWindow = pCtx->hasWindowOrGroup && pCtx->hasWindow;
2,147,483,647✔
8406

8407
  if (pInfo->hasResult && (!isWindow || !pInfo->isNull)) {
2,147,483,647✔
8408
    // If already has result for 'group by' or
8409
    // has non-null result for 'window', we can skip left data blocks.
8410
    goto _group_value_over;
2,147,483,647✔
8411
  }
8412

8413
  int32_t               valueRowIndex = -1;
2,147,483,647✔
8414
  SInputColumnInfoData* pInput = &pCtx->input;
2,147,483,647✔
8415
  SColumnInfoData*      pInputCol = pInput->pData[0];
2,147,483,647✔
8416

8417
  // try to find a non-null value
8418
  if (NULL != pInputCol->pData) {
2,147,483,647✔
8419
    if (isWindow) {
2,147,483,647✔
8420
      // for 'window', non-null value can appear at any row of any data block
8421
      int64_t startIndex = pInput->startRowIndex;
2,147,483,647✔
8422
      int64_t endIndex = pInput->startRowIndex + pInput->numOfRows - 1;
2,147,483,647✔
8423
      for (int64_t i = startIndex; i <= endIndex; ++i) {
2,147,483,647✔
8424
        if (!colDataIsNull_s(pInputCol, i)) {
2,147,483,647✔
8425
          valueRowIndex = i;
2,147,483,647✔
8426
          break;
2,147,483,647✔
8427
        }
8428
      }
8429
    } else {
8430
      // for 'group by', just take the first row
8431
      if (!colDataIsNull_s(pInputCol, pInput->startRowIndex)) {
416,263,408✔
8432
        valueRowIndex = pInput->startRowIndex;
205,945,760✔
8433
      }
8434
    }
8435
  }
8436

8437
  if (valueRowIndex != -1) {
2,147,483,647✔
8438
    // found a non-null value
8439
    char* data = colDataGetData(pInputCol, valueRowIndex);
2,147,483,647✔
8440
    if (IS_VAR_DATA_TYPE(pInputCol->info.type)) {
2,147,483,647✔
8441
      int32_t bytes = calcStrBytesByType(pInputCol->info.type, data);
2,147,483,647✔
8442
      (void)memcpy(pInfo->data, data, bytes);
2,147,483,647✔
8443
    } else {
8444
      (void)memcpy(pInfo->data, data, pInputCol->info.bytes);
2,147,483,647✔
8445
    }
8446
    pInfo->isNull = false;
2,147,483,647✔
8447
  } else {
8448
    // all values are null or first value is null for group by
8449
    pInfo->isNull = true;
749,026,030✔
8450
  }
8451
  pInfo->hasResult = true;
2,147,483,647✔
8452

8453
_group_value_over:
2,147,483,647✔
8454
  SET_VAL(pResInfo, 1, 1);
2,147,483,647✔
8455
  return TSDB_CODE_SUCCESS;
2,147,483,647✔
8456
}
8457

8458
int32_t groupKeyFunction(SqlFunctionCtx* pCtx) { return groupConstValueFunction(pCtx); }
2,147,483,647✔
8459

8460
int32_t groupConstValueFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
2,147,483,647✔
8461
  int32_t          slotId = pCtx->pExpr->base.resSchema.slotId;
2,147,483,647✔
8462
  int32_t          code = TSDB_CODE_SUCCESS;
2,147,483,647✔
8463
  SColumnInfoData* pCol = taosArrayGet(pBlock->pDataBlock, slotId);
2,147,483,647✔
8464
  if (NULL == pCol) {
2,147,483,647✔
8465
    return TSDB_CODE_OUT_OF_RANGE;
×
8466
  }
8467

8468
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
2,147,483,647✔
8469

8470
  SGroupKeyInfo* pInfo = GET_ROWCELL_INTERBUF(pResInfo);
2,147,483,647✔
8471

8472
  if (pInfo->hasResult) {
2,147,483,647✔
8473
    int32_t currentRow = pBlock->info.rows;
2,147,483,647✔
8474
    for (; currentRow < pBlock->info.rows + pResInfo->numOfRes; ++currentRow) {
2,147,483,647✔
8475
      code = colDataSetVal(pCol, currentRow, pInfo->data, pInfo->isNull ? true : false);
2,147,483,647✔
8476
      if (TSDB_CODE_SUCCESS != code) {
2,147,483,647✔
8477
        return code;
×
8478
      }
8479
    }
8480
  } else {
8481
    pResInfo->numOfRes = 0;
×
8482
  }
8483

8484
  return code;
2,147,483,647✔
8485
}
8486

8487
int32_t groupKeyFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) { return groupConstValueFinalize(pCtx, pBlock); }
2,147,483,647✔
8488

8489
int32_t groupKeyCombine(SqlFunctionCtx* pDestCtx, SqlFunctionCtx* pSourceCtx) {
×
8490
  SResultRowEntryInfo* pDResInfo = GET_RES_INFO(pDestCtx);
×
8491
  SGroupKeyInfo*       pDBuf = GET_ROWCELL_INTERBUF(pDResInfo);
×
8492

8493
  SResultRowEntryInfo* pSResInfo = GET_RES_INFO(pSourceCtx);
×
8494
  SGroupKeyInfo*       pSBuf = GET_ROWCELL_INTERBUF(pSResInfo);
×
8495

8496
  // escape rest of data blocks to avoid first entry to be overwritten.
8497
  if (pDBuf->hasResult) {
×
8498
    goto _group_key_over;
×
8499
  }
8500

8501
  if (pSBuf->isNull) {
×
8502
    pDBuf->isNull = true;
×
8503
    pDBuf->hasResult = true;
×
8504
    goto _group_key_over;
×
8505
  }
8506

8507
  if (IS_VAR_DATA_TYPE(pSourceCtx->resDataInfo.type)) {
×
8508
    int32_t bytes = calcStrBytesByType(pSourceCtx->resDataInfo.type, pSBuf->data);
×
8509
    (void)memcpy(pDBuf->data, pSBuf->data, bytes);
×
8510
  } else {
8511
    (void)memcpy(pDBuf->data, pSBuf->data, pSourceCtx->resDataInfo.bytes);
×
8512
  }
8513

8514
  pDBuf->hasResult = true;
×
8515

8516
_group_key_over:
×
8517

8518
  SET_VAL(pDResInfo, 1, 1);
×
8519
  return TSDB_CODE_SUCCESS;
×
8520
}
8521

8522
int32_t cachedLastRowFunction(SqlFunctionCtx* pCtx) {
812,899✔
8523
  int32_t numOfElems = 0;
812,899✔
8524

8525
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
812,899✔
8526
  SFirstLastRes*       pInfo = GET_ROWCELL_INTERBUF(pResInfo);
812,899✔
8527

8528
  SInputColumnInfoData* pInput = &pCtx->input;
812,899✔
8529
  SColumnInfoData*      pInputCol = pInput->pData[0];
812,899✔
8530

8531
  int32_t bytes = pInputCol->info.bytes;
812,899✔
8532
  pInfo->bytes = bytes;
812,899✔
8533

8534
  SColumnInfoData* pkCol = pInput->pPrimaryKey;
812,899✔
8535
  pInfo->pkType = -1;
812,899✔
8536
  __compar_fn_t pkCompareFn = NULL;
812,899✔
8537
  if (pCtx->hasPrimaryKey) {
812,899✔
8538
    pInfo->pkType = pkCol->info.type;
414,136✔
8539
    pInfo->pkBytes = pkCol->info.bytes;
414,136✔
8540
    pkCompareFn = getKeyComparFunc(pInfo->pkType, TSDB_ORDER_DESC);
414,136✔
8541
  }
8542

8543
  // data is guaranteed to be in descending order
8544
  for (int32_t i = pInput->numOfRows + pInput->startRowIndex - 1; i >= pInput->startRowIndex; --i) {
1,684,591✔
8545
    numOfElems++;
871,692✔
8546

8547
    bool  isNull = colDataIsNull(pInputCol, pInput->numOfRows, i, NULL);
871,692✔
8548
    char* data = isNull ? NULL : colDataGetData(pInputCol, i);
871,692✔
8549

8550
    TSKEY cts = getRowPTs(pInput->pPTS, i);
871,692✔
8551
    if (pResInfo->numOfRes == 0 || pInfo->ts < cts) {
871,692✔
8552
      int32_t code = doSaveLastrow(pCtx, data, i, cts, pInfo);
517,126✔
8553
      if (code != TSDB_CODE_SUCCESS) {
517,126✔
8554
        return code;
×
8555
      }
8556
      pResInfo->numOfRes = 1;
517,126✔
8557
    }
8558
  }
8559

8560
  SET_VAL(pResInfo, numOfElems, 1);
812,899✔
8561
  return TSDB_CODE_SUCCESS;
812,899✔
8562
}
8563

8564
bool getCorrFuncEnv(SFunctionNode* pFunc, SFuncExecEnv* pEnv) {
×
8565
  pEnv->calcMemSize = sizeof(SCorrRes);
×
8566
  return true;
×
8567
}
8568

8569
int32_t corrFuncSetup(SqlFunctionCtx* pCtx, SResultRowEntryInfo* pResultInfo) {
×
8570
  if (pResultInfo->initialized) {
×
8571
    return TSDB_CODE_SUCCESS;
×
8572
  }
8573
  if (TSDB_CODE_SUCCESS != functionSetup(pCtx, pResultInfo)) {
×
8574
    return TSDB_CODE_FUNC_SETUP_ERROR;
×
8575
  }
8576

8577
  SCorrRes* pRes = GET_ROWCELL_INTERBUF(pResultInfo);
×
8578
  (void)memset(pRes, 0, sizeof(SCorrRes));
×
8579
  return TSDB_CODE_SUCCESS;
×
8580
}
8581

8582
int32_t corrFunction(SqlFunctionCtx* pCtx) {
×
8583
  int32_t               numOfElem = 0;
×
8584
  SInputColumnInfoData* pInput = &pCtx->input;
×
8585
  int32_t               xType = pInput->pData[0]->info.type;
×
8586
  int32_t               yType = pInput->pData[1]->info.type;
×
8587
  SCorrRes*             pCorrRes = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
×
8588

8589
  // computing based on the true data block
8590
  SColumnInfoData* pLeft = pInput->pData[0];   // left
×
8591
  SColumnInfoData* pRight = pInput->pData[1];  // right
×
8592

8593
  int32_t leftMod = typeGetTypeModFromColInfo(&pLeft->info);
×
8594
  int32_t rightMod = typeGetTypeModFromColInfo(&pRight->info);
×
8595
  int32_t start = pInput->startRowIndex;
×
8596
  int32_t numOfRows = pInput->numOfRows;
×
8597

8598
  if (IS_NULL_TYPE(xType) || IS_NULL_TYPE(yType)) {
×
8599
    numOfElem = 0;
×
8600
    goto _over;
×
8601
  }
8602

8603
  for (int32_t i = 0; i < numOfRows; ++i) {
×
8604
    double pInputX = 0, pInputY = 0;
×
8605

8606
    if (colDataIsNull_f(pLeft, i) || colDataIsNull_f(pRight, i)) {
×
8607
      continue;
×
8608
    }
8609

8610
    char* pXVal = colDataGetData(pLeft, i);
×
8611
    char* pYVal = colDataGetData(pRight, i);
×
8612

8613
    GET_TYPED_DATA(pInputX, double, xType, pXVal, leftMod);
×
8614
    GET_TYPED_DATA(pInputY, double, yType, pYVal, rightMod);
×
8615

8616
    pCorrRes->sumLeft += pInputX;
×
8617
    pCorrRes->sumRight += pInputY;
×
8618

8619
    pCorrRes->quadLeft += pInputX * pInputX;
×
8620
    pCorrRes->quadRight += pInputY * pInputY;
×
8621

8622
    pCorrRes->productVal += pInputX * pInputY;
×
8623

8624
    pCorrRes->count += 1;
×
8625
    numOfElem += 1;
×
8626
  }
8627

8628
_over:
×
8629
  // data in the check operation are all null, not output
8630
  SET_VAL(GET_RES_INFO(pCtx), numOfElem, 1);
×
8631
  return TSDB_CODE_SUCCESS;
×
8632
}
8633

8634
int32_t corrFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
×
8635
  SInputColumnInfoData* pInput = &pCtx->input;
×
8636
  SCorrRes*             pRes = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
×
8637
  double                avg;
8638

8639
  if (pRes->count == 0) {
×
8640
    GET_RES_INFO(pCtx)->numOfRes = 0;
×
8641
    return functionFinalize(pCtx, pBlock);
×
8642
  }
8643

8644
  /**
8645
    numerator = sum_xy - (sum_x * sum_y) / n
8646
    denominator_x = math.sqrt(sum_x2 - (sum_x**2) / n)
8647
    denominator_y = math.sqrt(sum_y2 - (sum_y**2) / n)
8648

8649
    if denominator_x == 0 or denominator_y == 0:
8650
        return 0.0
8651
    res = numerator / (denominator_x * denominator_y)
8652
  */
8653

8654
  if (pRes->count == 1) {
×
8655
    pRes->result = 0.0;
×
8656
  } else {
8657
    double numerator = pRes->productVal - (pRes->sumLeft * pRes->sumRight) / pRes->count;
×
8658
    double dnmX = sqrt(pRes->quadLeft - pRes->sumLeft * pRes->sumLeft / pRes->count);
×
8659
    double dnmY = sqrt(pRes->quadRight - pRes->sumRight * pRes->sumRight / pRes->count);
×
8660

8661
    if (DBL_EQUAL(dnmX, 0.0) || DBL_EQUAL(dnmY, 0.0)) {
×
8662
      pRes->result = 0.0;
×
8663
    } else {
8664
      pRes->result = numerator / (dnmX * dnmY);
×
8665

8666
      if (pRes->result > 1 || pRes->result < -1) {
×
8667
        qError("invalid corr results, %.4f, numerator:%.4f, dnmX:%.4f, dnmY:%.4f", pRes->result, numerator, dnmX, dnmY);
×
8668
        if (pRes->result > 1) {
×
8669
          pRes->result = 1;
×
8670
        } else if (pRes->result < -1) {
×
8671
          pRes->result = -1;
×
8672
        }
8673
      }
8674
    }
8675
  }
8676

8677
  return functionFinalize(pCtx, pBlock);
×
8678
}
8679

8680
int32_t getCorrInfoSize() { return sizeof(SCorrRes); }
×
8681

8682
int32_t corrPartialFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
×
8683
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
×
8684
  SStdRes*             pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
×
8685
  int32_t              resultBytes = getCorrInfoSize();
×
8686
  char*                res = taosMemoryCalloc(resultBytes + VARSTR_HEADER_SIZE, sizeof(char));
×
8687
  int32_t              slotId = pCtx->pExpr->base.resSchema.slotId;
×
8688
  int32_t              code = 0;
×
8689

8690
  if (NULL == res) {
×
8691
    return terrno;
×
8692
  }
8693

8694
  (void)memcpy(varDataVal(res), pInfo, resultBytes);
×
8695
  varDataSetLen(res, resultBytes);
×
8696

8697
  SColumnInfoData* pCol = taosArrayGet(pBlock->pDataBlock, slotId);
×
8698
  if (NULL == pCol) {
×
8699
    taosMemoryFree(res);
×
8700
    return TSDB_CODE_OUT_OF_RANGE;
×
8701
  }
8702

8703
  code = colDataSetVal(pCol, pBlock->info.rows, res, false);
×
8704

8705
  taosMemoryFree(res);
×
8706
  return code;
×
8707
}
8708

8709
int32_t corrFuncMerge(SqlFunctionCtx* pCtx) {
×
8710
  SInputColumnInfoData* pInput = &pCtx->input;
×
8711
  SColumnInfoData*      pCol = pInput->pData[0];
×
8712

8713
  if (IS_NULL_TYPE(pCol->info.type)) {
×
8714
    SET_VAL(GET_RES_INFO(pCtx), 0, 1);
×
8715
    return TSDB_CODE_SUCCESS;
×
8716
  }
8717

8718
  if (pCol->info.type != TSDB_DATA_TYPE_BINARY) {
×
8719
    return TSDB_CODE_FUNC_FUNTION_PARA_TYPE;
×
8720
  }
8721

8722
  SCorrRes* pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
×
8723

8724
  for (int32_t i = pInput->startRowIndex; i < pInput->startRowIndex + pInput->numOfRows; ++i) {
×
8725
    if (colDataIsNull_s(pCol, i)) {
×
8726
      continue;
×
8727
    }
8728

8729
    char*     data = colDataGetData(pCol, i);
×
8730
    SCorrRes* pInputInfo = (SCorrRes*)varDataVal(data);
×
8731

8732
    if (pInputInfo->count == 0) {
×
8733
      continue;
×
8734
    }
8735

8736
    // pOutput->type = pInput->type;
8737
    if (pInfo->count == 0) {
×
8738
      TAOS_MEMCPY(pInfo, pInputInfo, sizeof(SCorrRes));
×
8739
    } else if (pInfo->count > 0) {
×
8740
      pInfo->productVal += pInputInfo->productVal;
×
8741
      pInfo->quadLeft += pInputInfo->quadLeft;
×
8742
      pInfo->quadRight += pInputInfo->quadRight;
×
8743
      pInfo->sumLeft += pInputInfo->sumLeft;
×
8744
      pInfo->sumRight += pInputInfo->sumRight;
×
8745
      pInfo->count += pInputInfo->count;
×
8746
    }
8747
  }
8748

8749
  SET_VAL(GET_RES_INFO(pCtx), pInfo->count, 1);
×
8750
  return TSDB_CODE_SUCCESS;
×
8751
}
8752

8753
int32_t hasNullFunction(SqlFunctionCtx* pCtx) {
15,703,834✔
8754
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
15,703,834✔
8755
  bool* pRes = GET_ROWCELL_INTERBUF(pResInfo);
15,703,834✔
8756
  if (*pRes) {
15,703,834✔
8757
    return TSDB_CODE_SUCCESS;
×
8758
  }
8759

8760
  SInputColumnInfoData* pInput = &pCtx->input;
15,703,834✔
8761
  SColumnDataAgg*       pAgg = pInput->pColumnDataAgg[0];
15,703,834✔
8762
  SColumnInfoData* pCol = pInput->pData[0];
15,703,834✔
8763

8764
  if (pInput->numOfRows > 0) {
15,703,834✔
8765
    pResInfo->numOfRes = 1;
15,703,834✔
8766
  }
8767

8768
  if (IS_NULL_TYPE(pCol->info.type) && pInput->numOfRows > 0) {
15,703,834✔
8769
    *pRes = true;
×
8770
    return TSDB_CODE_SUCCESS;
×
8771
  }
8772

8773
  if (pInput->colDataSMAIsSet) {
15,703,834✔
8774
    if (pAgg->numOfNull > 0) {
×
8775
      *pRes = true;
×
8776
      return TSDB_CODE_SUCCESS;
×
8777
    }
8778

8779
    if (pInput->numOfRows <= INT16_MAX) {
×
8780
      return TSDB_CODE_SUCCESS;
×
8781
    }
8782
  }
8783

8784
  int32_t start = pInput->startRowIndex;
15,703,834✔
8785
  int32_t end = start + pInput->numOfRows;
15,703,834✔
8786

8787
  if (pCol->hasNull) {
15,703,834✔
8788
    for (int32_t i = start; i < end; ++i) {
37,381,594✔
8789
      if (colDataIsNull_s(pCol, i)) {
63,379,892✔
8790
        *pRes = true;
9,921,384✔
8791
        break;
9,921,384✔
8792
      }
8793
    }
8794
  }  
8795

8796
  return TSDB_CODE_SUCCESS;
15,703,834✔
8797
}
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