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

taosdata / TDengine / #5059

17 May 2026 01:15AM UTC coverage: 73.443% (+0.06%) from 73.387%
#5059

push

travis-ci

web-flow
feat (TDgpt): Dynamic Model Synchronization Enhancements (#35344)

* refactor: do some internal refactor.

* fix: fix multiprocess sync issue.

* feat: add dynamic anomaly detection and forecasting services

* fix: log error message for undeploying model in exception handling

* Potential fix for pull request finding

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>

* Potential fix for pull request finding

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>

* Potential fix for pull request finding

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>

* Potential fix for pull request finding

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>

* fix: handle undeploy when model exists only on disk

Agent-Logs-Url: https://github.com/taosdata/TDengine/sessions/286aafa0-c3ce-4c27-b803-2707571e9dc1

Co-authored-by: hjxilinx <8252296+hjxilinx@users.noreply.github.com>

* fix: guard dynamic registry concurrent access

Agent-Logs-Url: https://github.com/taosdata/TDengine/sessions/5e4db858-6458-40f4-ac28-d1b1b7f97c18

Co-authored-by: hjxilinx <8252296+hjxilinx@users.noreply.github.com>

* fix: tighten service list locking scope

Agent-Logs-Url: https://github.com/taosdata/TDengine/sessions/5e4db858-6458-40f4-ac28-d1b1b7f97c18

Co-authored-by: hjxilinx <8252296+hjxilinx@users.noreply.github.com>

* fix: restore prophet support and update tests per review feedback

Agent-Logs-Url: https://github.com/taosdata/TDengine/sessions/92298ae1-7da6-4d07-b20e-101c7cd0b26b

Co-authored-by: hjxilinx <8252296+hjxilinx@users.noreply.github.com>

* fix: improve test name and move copy inside lock scope

Agent-Logs-Url: https://github.com/taosdata/TDengine/sessions/92298ae1-7da6-4d07-b20e-101c7cd0b26b

Co-authored-by: hjxilinx <8252296+hjxilinx@users.noreply.github.com>

* Potential fix for pull request finding

Co-au... (continued)

281870 of 383795 relevant lines covered (73.44%)

135516561.93 hits per line

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

75.93
/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; }
60,652,417✔
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) {
72,059,793✔
200
  SFuncInputRowIter* pIter = &pCtx->rowIter;
72,059,793✔
201

202
  if (!pCtx->bInputFinished) {
72,059,793✔
203
    pIter->pInput = &pCtx->input;
72,059,793✔
204
    pIter->tsList = (TSKEY*)pIter->pInput->pPTS->pData;
72,059,793✔
205
    pIter->pDataCol = pIter->pInput->pData[0];
72,059,793✔
206
    pIter->pPkCol = pIter->pInput->pPrimaryKey;
72,059,793✔
207
    pIter->rowIndex = pIter->pInput->startRowIndex;
72,059,793✔
208
    pIter->inputEndIndex = pIter->rowIndex + pIter->pInput->numOfRows - 1;
72,059,793✔
209
    pIter->pSrcBlock = pCtx->pSrcBlock;
72,059,793✔
210
    if (!pIter->hasGroupId || pIter->groupId != pIter->pSrcBlock->info.id.groupId) {
72,059,793✔
211
      pIter->hasGroupId = true;
7,630,022✔
212
      pIter->groupId = pIter->pSrcBlock->info.id.groupId;
7,630,022✔
213
      pIter->hasPrev = false;
7,630,022✔
214
    }
215
  } else {
216
    pIter->finalRow = true;
×
217
  }
218
}
72,059,793✔
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

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];
×
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];
×
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;
×
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) {
3,913,816✔
335
  int32_t idx = rowIndex + 1;
3,913,816✔
336
  while (idx <= pIter->inputEndIndex && pIter->tsList[idx] == pIter->tsList[rowIndex]) {
55,669,566✔
337
    ++idx;
51,755,750✔
338
  }
339
  pIter->rowIndex = idx;
3,913,816✔
340
}
3,913,816✔
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) {
5,211,494✔
353
  if (pIter->hasPrev) {
5,211,494✔
354
    if (pIter->prevBlockTsEnd == pIter->tsList[pIter->inputEndIndex]) {
412,920✔
355
      pIter->hasPrev = true;
×
356
      return false;
×
357
    } else {
358
      int32_t idx = pIter->rowIndex;
412,920✔
359
      while (pIter->tsList[idx] == pIter->prevBlockTsEnd) {
412,920✔
360
        ++idx;
×
361
      }
362

363
      pIter->hasPrev = false;
412,920✔
364
      setInputRowInfo(pRow, pIter, idx, true);
412,920✔
365
      forwardToNextDiffTsRow(pIter, idx);
412,920✔
366
      return true;
412,920✔
367
    }
368
  } else {
369
    if (pIter->rowIndex <= pIter->inputEndIndex) {
4,798,574✔
370
      setInputRowInfo(pRow, pIter, pIter->rowIndex, true);
4,150,224✔
371

372
      TSKEY tsEnd = pIter->tsList[pIter->inputEndIndex];
4,150,224✔
373
      if (pIter->tsList[pIter->rowIndex] != tsEnd) {
4,150,224✔
374
        forwardToNextDiffTsRow(pIter, pIter->rowIndex);
3,500,896✔
375
      } else {
376
        pIter->rowIndex = pIter->inputEndIndex + 1;
649,328✔
377
      }
378
      return true;
4,150,224✔
379
    } else {
380
      TSKEY tsEnd = pIter->tsList[pIter->inputEndIndex];
648,350✔
381
      pIter->hasPrev = true;
648,350✔
382
      pIter->prevBlockTsEnd = tsEnd;
648,350✔
383
      return false;
648,350✔
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;
72,350,755✔
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) {
5,211,494✔
402
      return funcInputGetNextRowDescPk(pIter, pRow, res);
×
403
      return TSDB_CODE_SUCCESS;
404
    } else {
405
      *res = funcInputGetNextRowAscPk(pIter, pRow);
5,211,494✔
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;
5,211,494✔
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,425✔
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
2,820,347✔
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) {
122,672✔
504
  int32_t          slotId = pCtx->pExpr->base.resSchema.slotId;
122,672✔
505
  SColumnInfoData* pCol = taosArrayGet(pBlock->pDataBlock, slotId);
122,672✔
506
  if (NULL == pCol) {
122,672✔
507
    return TSDB_CODE_OUT_OF_RANGE;
×
508
  }
509
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
122,672✔
510
  pResInfo->isNullRes = (pResInfo->numOfRes == 0) ? 1 : 0;
122,672✔
511

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

515
  return code;
122,672✔
516
}
517

518
EFuncDataRequired countDataRequired(SFunctionNode* pFunc, STimeWindow* pTimeWindow) {
16,471,519✔
519
  SNode* pParam = nodesListGetNode(pFunc->pParameterList, 0);
16,471,519✔
520
  if (QUERY_NODE_COLUMN == nodeType(pParam) && PRIMARYKEY_TIMESTAMP_COL_ID == ((SColumnNode*)pParam)->colId) {
16,473,966✔
521
    return FUNC_DATA_REQUIRED_NOT_LOAD;
12,031,976✔
522
  }
523
  return FUNC_DATA_REQUIRED_SMA_LOAD;
4,442,064✔
524
}
525

526
bool getCountFuncEnv(SFunctionNode* UNUSED_PARAM(pFunc), SFuncExecEnv* pEnv) {
58,166,083✔
527
  pEnv->calcMemSize = sizeof(int64_t);
58,166,083✔
528
  return true;
58,184,175✔
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;
59,873,902✔
543
  }
544
  if (pInput->colDataSMAIsSet && pInput->totalRows == pInput->numOfRows) {
2,147,483,647✔
545
    numOfElem = pInput->numOfRows - pInput->pColumnDataAgg[0]->numOfNull;
926,097✔
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;
39,590,323✔
580
    val += 0;
39,590,323✔
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,061,074✔
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;
583,366✔
622
    goto _sum_over;
583,366✔
623
  }
624

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

628
    if (IS_SIGNED_NUMERIC_TYPE(type)) {
32,021,404✔
629
      SUM_RES_INC_ISUM(pSumRes, pAgg->sum);
16,405,428✔
630
    } else if (IS_UNSIGNED_NUMERIC_TYPE(type)) {
15,615,976✔
631
      SUM_RES_INC_USUM(pSumRes, pAgg->sum);
15,588,597✔
632
    } else if (IS_FLOAT_TYPE(type)) {
34,601✔
633
      SUM_RES_INC_DSUM(pSumRes, GET_DOUBLE_VAL((const char*)&(pAgg->sum)));
33,160✔
634
    } else if (IS_DECIMAL_TYPE(type)) {
8,844✔
635
      SUM_RES_SET_TYPE(pSumRes, pCtx->inputType, TSDB_DATA_TYPE_DECIMAL);
8,844✔
636
      const SDecimalOps* pOps = getDecimalOps(TSDB_DATA_TYPE_DECIMAL);
8,844✔
637
      if (pAgg->overflow || decimal128AddCheckOverflow((Decimal*)&SUM_RES_GET_DECIMAL_SUM(pSumRes),
16,080✔
638
                                                       &pAgg->decimal128Sum, DECIMAL_WORD_NUM(Decimal))) {
7,236✔
639
        return TSDB_CODE_DECIMAL_OVERFLOW;
1,608✔
640
      }
641
      pOps->add(&SUM_RES_GET_DECIMAL_SUM(pSumRes), &pAgg->decimal128Sum, DECIMAL_WORD_NUM(Decimal));
7,236✔
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);
832,090,235✔
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);
654,597,233✔
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,393,086,524✔
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);
624,127,747✔
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) {
75,296,394✔
665
        LIST_ADD_N(SUM_RES_GET_USUM(pSumRes), pCol, start, numOfRows, uint32_t, numOfElem);
654,300,471✔
666
      } else if (type == TSDB_DATA_TYPE_UBIGINT) {
2,785,937✔
667
        LIST_ADD_N(SUM_RES_GET_USUM(pSumRes), pCol, start, numOfRows, uint64_t, numOfElem);
514,926,116✔
668
      }
669
    } else if (type == TSDB_DATA_TYPE_DOUBLE) {
242,651,923✔
670
      LIST_ADD_N(SUM_RES_GET_DSUM(pSumRes), pCol, start, numOfRows, double, numOfElem);
605,604,538✔
671
    } else if (type == TSDB_DATA_TYPE_FLOAT) {
154,678,346✔
672
      LIST_ADD_N(SUM_RES_GET_DSUM(pSumRes), pCol, start, numOfRows, float, numOfElem);
503,000,674✔
673
    } else if (IS_DECIMAL_TYPE(type)) {
32,746✔
674
      SUM_RES_SET_TYPE(pSumRes, pCtx->inputType, TSDB_DATA_TYPE_DECIMAL);
32,746✔
675
      int32_t overflow = false;
29,656✔
676
      if (TSDB_DATA_TYPE_DECIMAL64 == type) {
29,656✔
677
        LIST_ADD_DECIMAL_N(&SUM_RES_GET_DECIMAL_SUM(pSumRes), pCol, start, numOfRows, Decimal64, numOfElem);
6,458,500✔
678
      } else if (TSDB_DATA_TYPE_DECIMAL == type) {
17,688✔
679
        LIST_ADD_DECIMAL_N(&SUM_RES_GET_DECIMAL_SUM(pSumRes), pCol, start, numOfRows, Decimal128, numOfElem);
12,886,512✔
680
      }
681
      if (overflow) return TSDB_CODE_DECIMAL_OVERFLOW;
29,656✔
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;
×
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,383,017,818✔
693
        fmIsCountLikeFunc(pCtx->pExpr->pExpr->_function.pFunctNode->originalFuncId)) {
126,230,247✔
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) {
30,884,903✔
727
  pEnv->calcMemSize = SUM_RES_GET_SIZE(pFunc->node.resType.type);
30,884,903✔
728
  return true;
30,895,529✔
729
}
730

731
static bool funcNotSupportStringSma(SFunctionNode* pFunc) {
26,923,465✔
732
  SNode* pParam;
733
  switch (pFunc->funcType) {
26,923,465✔
734
    case FUNCTION_TYPE_MAX:
26,926,812✔
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);
26,926,812✔
746
      if (pParam && nodesIsExprNode(pParam) && (IS_VAR_DATA_TYPE(((SExprNode*)pParam)->resType.type))) {
26,928,322✔
747
        return true;
1,692,768✔
748
      }
749
      break;
25,235,083✔
750
    default:
×
751
      break;
×
752
  }
753
  return false;
25,231,736✔
754
}
755

756
EFuncDataRequired statisDataRequired(SFunctionNode* pFunc, STimeWindow* pTimeWindow) {
26,923,645✔
757
  if (funcNotSupportStringSma(pFunc)) {
26,923,645✔
758
    return FUNC_DATA_REQUIRED_DATA_LOAD;
1,692,768✔
759
  }
760
  return FUNC_DATA_REQUIRED_SMA_LOAD;
25,235,300✔
761
}
762

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

771
  SMinmaxResInfo* buf = GET_ROWCELL_INTERBUF(pResultInfo);
2,125,605,364✔
772
  buf->assign = false;
2,125,592,294✔
773
  buf->tuplePos.pageId = -1;
2,125,608,858✔
774

775
  buf->nullTupleSaved = false;
2,125,608,988✔
776
  buf->nullTuplePos.pageId = -1;
2,125,607,052✔
777
  buf->str = NULL;
2,125,600,639✔
778
  return TSDB_CODE_SUCCESS;
2,125,612,116✔
779
}
780

781
bool getMinmaxFuncEnv(SFunctionNode* UNUSED_PARAM(pFunc), SFuncExecEnv* pEnv) {
46,840,404✔
782
  COMPILE_TIME_ASSERT(sizeof(SMinmaxResInfo) == sizeof(SOldMinMaxResInfo));
783
  pEnv->calcMemSize = sizeof(SMinmaxResInfo);
46,840,404✔
784
  return true;
46,844,310✔
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,088,241,894✔
812
  int32_t code = TSDB_CODE_SUCCESS;
2,088,241,894✔
813

814
  SResultRowEntryInfo* pEntryInfo = GET_RES_INFO(pCtx);
2,088,241,894✔
815
  SMinmaxResInfo*      pRes = GET_ROWCELL_INTERBUF(pEntryInfo);
2,088,242,123✔
816

817
  int32_t slotId = pCtx->pExpr->base.resSchema.slotId;
2,088,244,418✔
818
  int32_t currentRow = pBlock->info.rows;
2,088,243,164✔
819

820
  SColumnInfoData* pCol = taosArrayGet(pBlock->pDataBlock, slotId);
2,088,245,059✔
821
  if (NULL == pCol) {
2,088,242,815✔
822
    return TSDB_CODE_OUT_OF_RANGE;
×
823
  }
824
  pEntryInfo->isNullRes = (pEntryInfo->numOfRes == 0) ? 1 : 0;
2,088,242,815✔
825

826
  // NOTE: do nothing change it, for performance issue
827
  if (!pEntryInfo->isNullRes) {
2,088,243,748✔
828
    switch (pCol->info.type) {
1,804,986,965✔
829
      case TSDB_DATA_TYPE_UBIGINT:
148,919,252✔
830
      case TSDB_DATA_TYPE_BIGINT:
831
      case TSDB_DATA_TYPE_TIMESTAMP:
832
        ((int64_t*)pCol->pData)[currentRow] = pRes->v;
148,919,252✔
833
        break;
148,919,252✔
834
      case TSDB_DATA_TYPE_UINT:
1,524,965,048✔
835
      case TSDB_DATA_TYPE_INT:
836
        colDataSetInt32(pCol, currentRow, (int32_t*)&pRes->v);
1,524,965,048✔
837
        break;
1,524,964,545✔
838
      case TSDB_DATA_TYPE_USMALLINT:
26,395,717✔
839
      case TSDB_DATA_TYPE_SMALLINT:
840
        colDataSetInt16(pCol, currentRow, (int16_t*)&pRes->v);
26,395,717✔
841
        break;
26,395,717✔
842
      case TSDB_DATA_TYPE_BOOL:
35,922,142✔
843
      case TSDB_DATA_TYPE_UTINYINT:
844
      case TSDB_DATA_TYPE_TINYINT:
845
        colDataSetInt8(pCol, currentRow, (int8_t*)&pRes->v);
35,922,142✔
846
        break;
35,922,142✔
847
      case TSDB_DATA_TYPE_DOUBLE:
28,896,432✔
848
        colDataSetDouble(pCol, currentRow, (double*)&pRes->v);
28,896,432✔
849
        break;
28,896,432✔
850
      case TSDB_DATA_TYPE_FLOAT: {
33,937,759✔
851
        float v = GET_FLOAT_VAL(&pRes->v);
33,937,759✔
852
        colDataSetFloat(pCol, currentRow, &v);
33,937,759✔
853
        break;
33,937,759✔
854
      }
855
      case TSDB_DATA_TYPE_VARBINARY:
5,191,861✔
856
      case TSDB_DATA_TYPE_VARCHAR:
857
      case TSDB_DATA_TYPE_NCHAR: {
858
        code = colDataSetVal(pCol, currentRow, pRes->str, false);
5,191,861✔
859
        if (TSDB_CODE_SUCCESS != code) {
5,192,350✔
860
          return code;
×
861
        }
862
        break;
5,192,350✔
863
      }
864
      case TSDB_DATA_TYPE_DECIMAL64:
721,139✔
865
        code = colDataSetVal(pCol, currentRow, (const char*)&pRes->v, false);
721,139✔
866
        break;
721,139✔
867
      case TSDB_DATA_TYPE_DECIMAL:
37,725✔
868
        code = colDataSetVal(pCol, currentRow, (void*)pRes->dec, false);
37,725✔
869
        break;
37,725✔
870
    }
871
  } else {
872
    colDataSetNULL(pCol, currentRow);
283,254,215✔
873
  }
874

875
  if (IS_VAR_DATA_TYPE(pCol->info.type)) taosMemoryFreeClear(pRes->str);
2,088,241,297✔
876
  if (pCtx->subsidiaries.num > 0) {
2,088,242,640✔
877
    if (pEntryInfo->numOfRes > 0) {
2,397,073✔
878
      code = setSelectivityValue(pCtx, pBlock, &pRes->tuplePos, currentRow);
2,157,423✔
879
    } else {
880
      code = setNullSelectivityValue(pCtx, pBlock, currentRow);
239,650✔
881
    }
882
  }
883

884
  return code;
2,088,241,255✔
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) {
926,101✔
893
    SqlFunctionCtx* pc = pCtx->subsidiaries.pCtx[j];
602,903✔
894
    int32_t         dstSlotId = pc->pExpr->base.resSchema.slotId;
602,903✔
895

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

903
  return TSDB_CODE_SUCCESS;
323,755✔
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) ||
80,676,042✔
912
      (pCtx->saveHandle.pState && pTuplePos->streamTupleKey.ts > 0)) {
582✔
913
    int32_t numOfCols = pCtx->subsidiaries.num;
80,677,005✔
914
    char*   p = NULL;
80,676,042✔
915
    int32_t code = loadTupleData(pCtx, pTuplePos, &p);
80,675,553✔
916
    if (p == NULL || TSDB_CODE_SUCCESS != code) {
80,674,560✔
917
      qError("Load tuple data failed since %s, groupId:%" PRIu64 ", ts:%" PRId64, terrstr(),
×
918
             pTuplePos->streamTupleKey.groupId, pTuplePos->streamTupleKey.ts);
919
      return TSDB_CODE_NOT_FOUND;
×
920
    }
921

922
    bool* nullList = (bool*)p;
80,676,042✔
923
    char* pStart = (char*)(nullList + numOfCols * sizeof(bool));
80,676,042✔
924

925
    // todo set the offset value to optimize the performance.
926
    for (int32_t j = 0; j < numOfCols; ++j) {
264,512,339✔
927
      SqlFunctionCtx* pc = pCtx->subsidiaries.pCtx[j];
183,836,786✔
928
      int32_t         dstSlotId = pc->pExpr->base.resSchema.slotId;
183,836,297✔
929

930
      SColumnInfoData* pDstCol = taosArrayGet(pBlock->pDataBlock, dstSlotId);
183,837,368✔
931
      if (NULL == pDstCol) {
183,835,791✔
932
        return terrno;
×
933
      }
934
      if (nullList[j]) {
183,835,791✔
935
        colDataSetNULL(pDstCol, rowIndex);
59,299,368✔
936
      } else {
937
        code = colDataSetValOrCover(pDstCol, rowIndex, pStart, false);
124,535,460✔
938
        if (TSDB_CODE_SUCCESS != code) {
124,537,418✔
939
          return code;
×
940
        }
941
      }
942
      pStart += pDstCol->info.bytes;
183,836,786✔
943
    }
944
  }
945

946
  return TSDB_CODE_SUCCESS;
80,676,516✔
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,118,252✔
952
  if (pCtx->subsidiaries.num <= 0) {
1,118,252✔
953
    return TSDB_CODE_SUCCESS;
×
954
  }
955

956
  int32_t code = TSDB_CODE_SUCCESS;
1,118,252✔
957
  for (int32_t j = 0; j < pCtx->subsidiaries.num; ++j) {
2,533,006✔
958
    SqlFunctionCtx* pc = pCtx->subsidiaries.pCtx[j];
1,414,754✔
959

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

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

969
    char* pData = colDataGetData(pSrcCol, rowIndex);
1,414,754✔
970

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

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

979
    if (colDataIsNull_s(pSrcCol, rowIndex) == true) {
2,829,508✔
980
      colDataSetNULL(pDstCol, pos);
58,752✔
981
    } else {
982
      code = colDataSetVal(pDstCol, pos, pData, false);
1,356,002✔
983
      if (TSDB_CODE_SUCCESS != code) {
1,356,002✔
984
        return code;
×
985
      }
986
    }
987
  }
988
  return code;
1,118,252✔
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); }
19,493,305✔
1085

1086
bool getStdFuncEnv(SFunctionNode* pFunc, SFuncExecEnv* pEnv) {
4,356,047✔
1087
  pEnv->calcMemSize = sizeof(SStdRes);
4,356,047✔
1088
  return true;
4,360,544✔
1089
}
1090

1091
int32_t stdFunctionSetup(SqlFunctionCtx* pCtx, SResultRowEntryInfo* pResultInfo) {
526,649,297✔
1092
  if (pResultInfo->initialized) {
526,649,297✔
1093
    return TSDB_CODE_SUCCESS;
×
1094
  }
1095
  if (TSDB_CODE_SUCCESS != functionSetup(pCtx, pResultInfo)) {
526,651,773✔
1096
    return TSDB_CODE_FUNC_SETUP_ERROR;
×
1097
  }
1098

1099
  SStdRes* pRes = GET_ROWCELL_INTERBUF(pResultInfo);
526,652,315✔
1100
  (void)memset(pRes, 0, sizeof(SStdRes));
526,651,638✔
1101
  return TSDB_CODE_SUCCESS;
526,651,638✔
1102
}
1103

1104
int32_t stdFunction(SqlFunctionCtx* pCtx) {
1,092,511,929✔
1105
  int32_t numOfElem = 0;
1,092,511,929✔
1106

1107
  // Only the pre-computing information loaded and actual data does not loaded
1108
  SInputColumnInfoData* pInput = &pCtx->input;
1,092,511,929✔
1109
  int32_t               type = pInput->pData[0]->info.type;
1,092,518,210✔
1110

1111
  SStdRes* pStdRes = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
1,092,531,643✔
1112
  pStdRes->type = type;
1,092,527,249✔
1113

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

1117
  int32_t start = pInput->startRowIndex;
1,092,522,294✔
1118
  int32_t numOfRows = pInput->numOfRows;
1,092,523,084✔
1119

1120
  if (IS_NULL_TYPE(type)) {
1,092,526,893✔
1121
    numOfElem = 0;
94,570✔
1122
    goto _stddev_over;
94,570✔
1123
  }
1124

1125
  switch (type) {
1,092,432,323✔
1126
    case TSDB_DATA_TYPE_TINYINT: {
12,403,102✔
1127
      int8_t* plist = (int8_t*)pCol->pData;
12,403,102✔
1128
      for (int32_t i = start; i < numOfRows + start; ++i) {
2,147,483,647✔
1129
        if (pCol->hasNull && colDataIsNull_f(pCol, i)) {
2,147,483,647✔
1130
          continue;
1,564,831,383✔
1131
        }
1132

1133
        numOfElem += 1;
698,620,961✔
1134
        pStdRes->count += 1;
698,620,961✔
1135
        double nr = (double)plist[i];
706,452,227✔
1136
        if (pStdRes->count == 1) {
706,447,488✔
1137
          pStdRes->dsum = nr;
682,954✔
1138
        } else {
1139
          double          s_kminusone = pStdRes->dsum;
705,755,056✔
1140
          volatile double diff = nr - s_kminusone;
705,755,056✔
1141
          pStdRes->dsum = s_kminusone + diff / (double)pStdRes->count;
705,755,056✔
1142
          pStdRes->quadraticDSum += diff * (nr - pStdRes->dsum);
705,790,348✔
1143
        }
1144
      }
1145

1146
      break;
12,097,891✔
1147
    }
1148

1149
    case TSDB_DATA_TYPE_SMALLINT: {
967,426,626✔
1150
      int16_t* plist = (int16_t*)pCol->pData;
967,426,626✔
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,295,436,861✔
1157
        pStdRes->count += 1;
1,295,436,861✔
1158
        double nr = (double)plist[i];
1,304,915,835✔
1159
        if (pStdRes->count == 1) {
1,304,903,649✔
1160
          pStdRes->dsum = nr;
396,100,131✔
1161
        } else {
1162
          double          s_kminusone = pStdRes->dsum;
908,806,903✔
1163
          volatile double diff = nr - s_kminusone;
908,808,257✔
1164
          pStdRes->dsum = s_kminusone + diff / (double)pStdRes->count;
908,808,257✔
1165
          pStdRes->quadraticDSum += diff * (nr - pStdRes->dsum);
908,840,753✔
1166
        }
1167
      }
1168
      break;
967,428,929✔
1169
    }
1170

1171
    case TSDB_DATA_TYPE_INT: {
18,815,298✔
1172
      int32_t* plist = (int32_t*)pCol->pData;
18,815,298✔
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;
822,598,202✔
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;
10,508,914✔
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;
18,815,975✔
1192
    }
1193

1194
    case TSDB_DATA_TYPE_BIGINT: {
20,903,892✔
1195
      int64_t* plist = (int64_t*)pCol->pData;
20,903,892✔
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,449,047,734✔
1199
        }
1200

1201
        numOfElem += 1;
928,878,138✔
1202
        pStdRes->count += 1;
928,878,138✔
1203
        double nr = (double)plist[i];
936,687,207✔
1204
        if (pStdRes->count == 1) {
936,698,083✔
1205
          pStdRes->dsum = nr;
1,883,421✔
1206
        } else {
1207
          double          s_kminusone = pStdRes->dsum;
934,794,952✔
1208
          volatile double diff = nr - s_kminusone;
934,820,056✔
1209
          pStdRes->dsum = s_kminusone + diff / (double)pStdRes->count;
934,820,056✔
1210
          pStdRes->quadraticDSum += diff * (nr - pStdRes->dsum);
934,739,306✔
1211
        }
1212
      }
1213
      break;
20,901,850✔
1214
    }
1215

1216
    case TSDB_DATA_TYPE_UTINYINT: {
13,986,457✔
1217
      uint8_t* plist = (uint8_t*)pCol->pData;
13,986,457✔
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,698,398,965✔
1221
        }
1222

1223
        numOfElem += 1;
1,104,310,133✔
1224
        pStdRes->count += 1;
1,104,310,133✔
1225
        double nr = (double)plist[i];
1,111,196,564✔
1226
        if (pStdRes->count == 1) {
1,111,049,804✔
1227
          pStdRes->dsum = nr;
80,331✔
1228
        } else {
1229
          double          s_kminusone = pStdRes->dsum;
1,111,069,014✔
1230
          volatile double diff = nr - s_kminusone;
1,110,525,129✔
1231
          pStdRes->dsum = s_kminusone + diff / (double)pStdRes->count;
1,110,525,129✔
1232
          pStdRes->quadraticDSum += diff * (nr - pStdRes->dsum);
1,111,011,992✔
1233
        }
1234
      }
1235

1236
      break;
13,682,430✔
1237
    }
1238

1239
    case TSDB_DATA_TYPE_USMALLINT: {
11,267,157✔
1240
      uint16_t* plist = (uint16_t*)pCol->pData;
11,267,157✔
1241
      for (int32_t i = start; i < numOfRows + pInput->startRowIndex; ++i) {
2,147,483,647✔
1242
        if (pCol->hasNull && colDataIsNull_f(pCol, i)) {
2,147,483,647✔
1243
          continue;
1,699,141,497✔
1244
        }
1245

1246
        numOfElem += 1;
549,636,146✔
1247
        pStdRes->count += 1;
549,636,146✔
1248
        double nr = (double)plist[i];
566,192,314✔
1249
        if (pStdRes->count == 1) {
566,192,991✔
1250
          pStdRes->dsum = nr;
35,110✔
1251
        } else {
1252
          double          s_kminusone = pStdRes->dsum;
566,162,620✔
1253
          volatile double diff = nr - s_kminusone;
566,158,558✔
1254
          pStdRes->dsum = s_kminusone + diff / (double)pStdRes->count;
566,158,558✔
1255
          pStdRes->quadraticDSum += diff * (nr - pStdRes->dsum);
566,172,098✔
1256
        }
1257
      }
1258
      break;
11,266,480✔
1259
    }
1260

1261
    case TSDB_DATA_TYPE_UINT: {
6,148,819✔
1262
      uint32_t* plist = (uint32_t*)pCol->pData;
6,148,819✔
1263
      for (int32_t i = start; i < numOfRows + pInput->startRowIndex; ++i) {
1,247,466,759✔
1264
        if (pCol->hasNull && colDataIsNull_f(pCol, i)) {
1,240,279,541✔
1265
          continue;
884,300,309✔
1266
        }
1267

1268
        numOfElem += 1;
355,732,501✔
1269
        pStdRes->count += 1;
355,732,501✔
1270
        double nr = (double)plist[i];
360,696,289✔
1271
        if (pStdRes->count == 1) {
360,701,028✔
1272
          pStdRes->dsum = nr;
25,978✔
1273
        } else {
1274
          double          s_kminusone = pStdRes->dsum;
360,660,156✔
1275
          volatile double diff = nr - s_kminusone;
360,672,342✔
1276
          pStdRes->dsum = s_kminusone + diff / (double)pStdRes->count;
360,672,342✔
1277
          pStdRes->quadraticDSum += diff * (nr - pStdRes->dsum);
360,661,510✔
1278
        }
1279
      }
1280

1281
      break;
6,148,819✔
1282
    }
1283

1284
    case TSDB_DATA_TYPE_UBIGINT: {
6,149,084✔
1285
      uint64_t* plist = (uint64_t*)pCol->pData;
6,149,084✔
1286
      for (int32_t i = start; i < numOfRows + pInput->startRowIndex; ++i) {
1,245,822,094✔
1287
        if (pCol->hasNull && colDataIsNull_f(pCol, i)) {
1,239,767,944✔
1288
          continue;
950,531,739✔
1289
        }
1290

1291
        numOfElem += 1;
288,851,994✔
1292
        pStdRes->count += 1;
288,851,994✔
1293
        double nr = (double)plist[i];
293,152,916✔
1294
        if (pStdRes->count == 1) {
293,122,000✔
1295
          pStdRes->dsum = nr;
22,847✔
1296
        } else {
1297
          double          s_kminusone = pStdRes->dsum;
293,110,772✔
1298
          volatile double diff = nr - s_kminusone;
293,115,588✔
1299
          pStdRes->dsum = s_kminusone + diff / (double)pStdRes->count;
293,115,588✔
1300
          pStdRes->quadraticDSum += diff * (nr - pStdRes->dsum);
293,119,639✔
1301
        }
1302
      }
1303
      break;
6,147,730✔
1304
    }
1305

1306
    case TSDB_DATA_TYPE_FLOAT: {
18,288,411✔
1307
      float* plist = (float*)pCol->pData;
18,288,411✔
1308
      for (int32_t i = start; i < numOfRows + pInput->startRowIndex; ++i) {
2,050,678,606✔
1309
        if (pCol->hasNull && colDataIsNull_f(pCol, i)) {
2,032,404,527✔
1310
          continue;
2,861,219✔
1311
        }
1312

1313
        numOfElem += 1;
2,029,531,665✔
1314
        pStdRes->count += 1;
2,029,531,665✔
1315
        double nr = (double)plist[i];
2,029,517,104✔
1316
        if (pStdRes->count == 1) {
2,029,519,375✔
1317
          pStdRes->dsum = nr;
17,416,182✔
1318
        } else {
1319
          double          s_kminusone = pStdRes->dsum;
2,012,110,506✔
1320
          volatile double diff = nr - s_kminusone;
2,012,108,461✔
1321
          pStdRes->dsum = s_kminusone + diff / (double)pStdRes->count;
2,012,108,461✔
1322
          pStdRes->quadraticDSum += diff * (nr - pStdRes->dsum);
2,012,111,376✔
1323
        }
1324
      }
1325
      break;
18,289,603✔
1326
    }
1327

1328
    case TSDB_DATA_TYPE_DOUBLE: {
17,043,477✔
1329
      double* plist = (double*)pCol->pData;
17,043,477✔
1330
      for (int32_t i = start; i < numOfRows + pInput->startRowIndex; ++i) {
329,139,014✔
1331
        if (pCol->hasNull && colDataIsNull_f(pCol, i)) {
312,105,524✔
1332
          continue;
90,319,370✔
1333
        }
1334

1335
        numOfElem += 1;
221,782,578✔
1336
        pStdRes->count += 1;
221,782,578✔
1337
        double nr = (double)plist[i];
221,787,942✔
1338
        if (pStdRes->count == 1) {
221,787,942✔
1339
          pStdRes->dsum = nr;
13,219,366✔
1340
        } else {
1341
          double          s_kminusone = pStdRes->dsum;
208,571,517✔
1342
          volatile double diff = nr - s_kminusone;
208,571,517✔
1343
          pStdRes->dsum = s_kminusone + diff / (double)pStdRes->count;
208,571,517✔
1344
          pStdRes->quadraticDSum += diff * (nr - pStdRes->dsum);
208,571,517✔
1345
        }
1346
      }
1347
      break;
17,045,265✔
1348
    }
1349

1350
    default:
×
1351
      break;
×
1352
  }
1353

1354
_stddev_over:
1,091,919,542✔
1355
  // data in the check operation are all null, not output
1356
  SET_VAL(GET_RES_INFO(pCtx), numOfElem, 1);
1,091,919,542✔
1357
  return TSDB_CODE_SUCCESS;
1,092,511,246✔
1358
}
1359

1360
static void stdTransferInfo(SStdRes* pInput, SStdRes* pOutput) {
18,751,289✔
1361
  if (IS_NULL_TYPE(pInput->type)) {
18,751,289✔
1362
    return;
27,290✔
1363
  }
1364
  pOutput->type = pInput->type;
18,723,999✔
1365
  if (pOutput->count == 0) {
18,723,999✔
1366
    pOutput->quadraticDSum += pInput->quadraticDSum;
18,397,999✔
1367
    pOutput->dsum += pInput->dsum;
18,397,999✔
1368
    pOutput->count = pInput->count;
18,397,999✔
1369
  } else if (pInput->count > 0) {
326,000✔
1370
    double totalCount = pOutput->count + pInput->count;
148,863✔
1371
    double totalSum = pInput->count * pInput->dsum + pOutput->count * pOutput->dsum;
148,863✔
1372
    double mean = totalSum / totalCount;
148,863✔
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;
148,863✔
1380
    pOutput->quadraticDSum += pInput->quadraticDSum + pInput->count * pOutput->count * (diff * diff) / totalCount;
148,863✔
1381
    pOutput->dsum = mean;
148,863✔
1382
    pOutput->count += pInput->count;
148,863✔
1383
  }
1384
}
1385

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

1390
  if (IS_NULL_TYPE(pCol->info.type)) {
18,722,559✔
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) {
18,722,559✔
1396
    return TSDB_CODE_FUNC_FUNTION_PARA_TYPE;
×
1397
  }
1398

1399
  SStdRes* pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
18,722,559✔
1400

1401
  for (int32_t i = pInput->startRowIndex; i < pInput->startRowIndex + pInput->numOfRows; ++i) {
37,473,848✔
1402
    if (colDataIsNull_s(pCol, i)) continue;
37,502,578✔
1403
    char*    data = colDataGetData(pCol, i);
18,751,289✔
1404
    SStdRes* pInputInfo = (SStdRes*)varDataVal(data);
18,751,289✔
1405
    stdTransferInfo(pInputInfo, pInfo);
18,751,289✔
1406
  }
1407

1408
  SET_VAL(GET_RES_INFO(pCtx), 1, 1);
18,722,559✔
1409
  return TSDB_CODE_SUCCESS;
18,722,559✔
1410
}
1411

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

1418
  if (pStddevRes->count == 0) {
481,662,767✔
1419
    GET_RES_INFO(pCtx)->numOfRes = 0;
66,201,824✔
1420

1421
    return functionFinalize(pCtx, pBlock);
66,201,228✔
1422
  }
1423

1424
  if (pStddevRes->count == 1) {
415,460,943✔
1425
    pStddevRes->result = 0.0;
283,565,922✔
1426
  } else {
1427
    pStddevRes->result = sqrt(pStddevRes->quadraticDSum / pStddevRes->count);
131,895,021✔
1428
  }
1429

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

1435
  return functionFinalize(pCtx, pBlock);
415,460,943✔
1436
}
1437

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

1444
  if (pStdvarRes->count == 0) {
7,253,526✔
1445
    GET_RES_INFO(pCtx)->numOfRes = 0;
9,214✔
1446
    return functionFinalize(pCtx, pBlock);
9,214✔
1447
  }
1448

1449
  if (pStdvarRes->count == 1) {
7,244,312✔
1450
    pStdvarRes->result = 0.0;
1,024✔
1451
  } else {
1452
    pStdvarRes->result = pStdvarRes->quadraticDSum / pStdvarRes->count;
7,243,288✔
1453
  }
1454

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

1460
  return functionFinalize(pCtx, pBlock);
7,244,312✔
1461
}
1462

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

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

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

1482
  int32_t code = colDataSetVal(pCol, pBlock->info.rows, res, false);
18,756,119✔
1483

1484
  taosMemoryFree(res);
18,756,119✔
1485
  return code;
18,756,119✔
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,573,503✔
1504
  SInputColumnInfoData* pInput = &pCtx->input;
3,573,503✔
1505
  SStdRes*              pStddevRes = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
3,573,503✔
1506
  double                avg;
1507

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

1513
  if (pStddevRes->count == 1) {
3,572,991✔
1514
    pStddevRes->result = 0.0;
512✔
1515
  } else {
1516
    pStddevRes->result = sqrt(pStddevRes->quadraticDSum / (pStddevRes->count - 1));
3,572,479✔
1517
  }
1518

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

1524
  return functionFinalize(pCtx, pBlock);
3,572,991✔
1525
}
1526

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

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

1537
  if (pStddevRes->count == 1) {
3,571,967✔
1538
    pStddevRes->result = 0.0;
512✔
1539
  } else {
1540
    pStddevRes->result = pStddevRes->quadraticDSum / (pStddevRes->count - 1);
3,571,455✔
1541
  }
1542

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

1548
  return functionFinalize(pCtx, pBlock);
3,571,967✔
1549
}
1550

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

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

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

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

1569
  int32_t sepParamIdx = pCtx->numOfParams - 1;
51,835✔
1570
  pRes->separator = pCtx->param[sepParamIdx].param.pz;
51,835✔
1571
  pRes->type = pCtx->param[sepParamIdx].param.nType;
51,835✔
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;
51,835✔
1581
}
1582

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

1608
  return TSDB_CODE_SUCCESS;
139,277✔
1609
}
1610

1611
int32_t gconcatFunction(SqlFunctionCtx* pCtx) {
51,311✔
1612
  int32_t               code = 0, numOfElem = 0;
51,311✔
1613
  SInputColumnInfoData* pInput = &pCtx->input;
51,311✔
1614
  int32_t               rowStart = pInput->startRowIndex;
51,311✔
1615
  int32_t               numOfRows = pInput->numOfRows;
51,311✔
1616
  int32_t               numOfCols = pInput->numOfInputCols;
51,311✔
1617
  SResultRowEntryInfo*  pResInfo = GET_RES_INFO(pCtx);
51,311✔
1618
  SGconcatRes*          pRes = GET_ROWCELL_INTERBUF(pResInfo);
51,311✔
1619
  char*                 sep = pRes->separator;
51,311✔
1620
  bool                  hasNchar = pRes->nchar;
51,311✔
1621
  VarDataLenT           dataLen = 0;
51,311✔
1622
  bool                  hasResultValue = (pResInfo->numOfRes > 0);
51,311✔
1623

1624
  if (!pRes->result) {
51,311✔
1625
    pRes->result = taosMemoryCalloc(1, TSDB_MAX_FIELD_LEN);
51,311✔
1626
    if (!pRes->result) {
51,311✔
1627
      return terrno;
×
1628
    }
1629

1630
    varDataSetLen(pRes->result, 0);
51,311✔
1631

1632
    for (int c = 0; c < numOfCols - 1; ++c) {
104,194✔
1633
      SColumnInfoData* pCol = pInput->pData[c];
52,883✔
1634
      int32_t          type = pCol->info.type;
52,883✔
1635

1636
      if (TSDB_DATA_TYPE_NCHAR == type) {
52,883✔
1637
        pRes->nchar = true;
33,304✔
1638
      }
1639
    }
1640
  } else {
1641
    dataLen = varDataLen(pRes->result);
×
1642
  }
1643

1644
  hasNchar = pRes->nchar;
51,311✔
1645

1646
  // computing based on the true data block
1647
  char*            buf = pRes->result;
51,311✔
1648
  SColumnInfoData* pCol = pInput->pData[numOfCols - 1];
51,311✔
1649

1650
  sep = colDataGetData(pCol, 0);
51,311✔
1651
  pRes->type = pCol->info.type;
51,311✔
1652
  for (int r = rowStart; r < rowStart + numOfRows; ++r) {
148,909✔
1653
    bool rowHasValue = false;
97,598✔
1654

1655
    for (int c = 0; c < numOfCols - 1; ++c) {
199,388✔
1656
      SColumnInfoData* pCol = pInput->pData[c];
101,790✔
1657
      int32_t          type = pCol->info.type;
101,790✔
1658

1659
      if (IS_NULL_TYPE(type) || colDataIsNull_s(pCol, r)) {
203,580✔
1660
        continue;
3,144✔
1661
      }
1662

1663
      if (!rowHasValue && hasResultValue) {
98,646✔
1664
        // concat the separator before the first non-null value of this row
1665
        code = gconcatHelper(sep, buf, hasNchar, pRes->type, &dataLen, NULL);
44,191✔
1666
        if (code) {
44,191✔
1667
          goto _over;
×
1668
        }
1669
      }
1670

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

1677
      rowHasValue = true;
98,646✔
1678
    }
1679

1680
    hasResultValue |= rowHasValue;
97,598✔
1681
  }
1682

1683
  varDataSetLen(buf, dataLen);
51,311✔
1684
  if (hasResultValue) {
51,311✔
1685
    numOfElem += 1;
50,263✔
1686
  }
1687

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

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

1702
  if (NULL == pCol) {
51,311✔
1703
    taosMemoryFree(pRes->result);
×
1704
    return TSDB_CODE_OUT_OF_RANGE;
×
1705
  }
1706

1707
  pResInfo->isNullRes = (pResInfo->numOfRes == 0) ? 1 : 0;
51,311✔
1708
  code = colDataSetVal(pCol, pBlock->info.rows, pRes->result, pResInfo->isNullRes);
51,311✔
1709

1710
  taosMemoryFree(pRes->result);
51,311✔
1711

1712
  return code;
51,311✔
1713
}
1714

1715
bool getLeastSQRFuncEnv(SFunctionNode* pFunc, SFuncExecEnv* pEnv) {
1,224,899✔
1716
  pEnv->calcMemSize = sizeof(SLeastSQRInfo);
1,224,899✔
1717
  return true;
1,224,899✔
1718
}
1719

1720
int32_t leastSQRFunctionSetup(SqlFunctionCtx* pCtx, SResultRowEntryInfo* pResultInfo) {
5,077,816✔
1721
  if (pResultInfo->initialized) {
5,077,816✔
1722
    return TSDB_CODE_SUCCESS;
×
1723
  }
1724
  if (TSDB_CODE_SUCCESS != functionSetup(pCtx, pResultInfo)) {
5,078,412✔
1725
    return TSDB_CODE_FUNC_SETUP_ERROR;
×
1726
  }
1727

1728
  SLeastSQRInfo* pInfo = GET_ROWCELL_INTERBUF(pResultInfo);
5,077,816✔
1729

1730
  GET_TYPED_DATA(pInfo->startVal, double, pCtx->param[1].param.nType, &pCtx->param[1].param.i,
5,077,816✔
1731
                 typeGetTypeModFromCol(pCtx->param[1].pCol));
1732
  GET_TYPED_DATA(pInfo->stepVal, double, pCtx->param[2].param.nType, &pCtx->param[2].param.i,
5,077,220✔
1733
                 typeGetTypeModFromCol(pCtx->param[2].pCol));
1734
  return TSDB_CODE_SUCCESS;
5,078,412✔
1735
}
1736

1737
int32_t leastSQRFunction(SqlFunctionCtx* pCtx) {
6,039,558✔
1738
  int32_t numOfElem = 0;
6,039,558✔
1739

1740
  SInputColumnInfoData* pInput = &pCtx->input;
6,039,558✔
1741
  int32_t               type = pInput->pData[0]->info.type;
6,039,558✔
1742

1743
  SLeastSQRInfo* pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
6,038,962✔
1744

1745
  SColumnInfoData* pCol = pInput->pData[0];
6,039,558✔
1746

1747
  double(*param)[3] = pInfo->matrix;
6,039,558✔
1748
  double x = pInfo->startVal;
6,039,558✔
1749

1750
  int32_t start = pInput->startRowIndex;
6,038,962✔
1751
  int32_t numOfRows = pInput->numOfRows;
6,039,558✔
1752

1753
  switch (type) {
6,037,174✔
1754
    case TSDB_DATA_TYPE_TINYINT: {
310,424✔
1755
      int8_t* plist = (int8_t*)pCol->pData;
310,424✔
1756
      for (int32_t i = start; i < numOfRows + pInput->startRowIndex; ++i) {
20,886,104✔
1757
        if (pCol->hasNull && colDataIsNull_f(pCol, i)) {
20,575,680✔
1758
          continue;
123,040✔
1759
        }
1760
        numOfElem++;
20,452,640✔
1761
        LEASTSQR_CAL(param, x, plist, i, pInfo->stepVal);
20,452,640✔
1762
      }
1763
      break;
310,424✔
1764
    }
1765
    case TSDB_DATA_TYPE_SMALLINT: {
3,129,751✔
1766
      int16_t* plist = (int16_t*)pCol->pData;
3,129,751✔
1767
      for (int32_t i = start; i < numOfRows + pInput->startRowIndex; ++i) {
111,840,959✔
1768
        if (pCol->hasNull && colDataIsNull_f(pCol, i)) {
108,710,016✔
1769
          continue;
88,134,932✔
1770
        }
1771

1772
        numOfElem++;
20,575,084✔
1773
        LEASTSQR_CAL(param, x, plist, i, pInfo->stepVal);
20,575,084✔
1774
      }
1775
      break;
3,130,347✔
1776
    }
1777

1778
    case TSDB_DATA_TYPE_INT: {
304,904✔
1779
      int32_t* plist = (int32_t*)pCol->pData;
304,904✔
1780
      for (int32_t i = start; i < numOfRows + pInput->startRowIndex; ++i) {
99,001,069✔
1781
        if (pCol->hasNull && colDataIsNull_f(pCol, i)) {
98,696,165✔
1782
          continue;
265,234✔
1783
        }
1784

1785
        numOfElem++;
98,430,931✔
1786
        LEASTSQR_CAL(param, x, plist, i, pInfo->stepVal);
98,430,931✔
1787
      }
1788
      break;
304,904✔
1789
    }
1790

1791
    case TSDB_DATA_TYPE_BIGINT: {
306,219✔
1792
      int64_t* plist = (int64_t*)pCol->pData;
306,219✔
1793
      for (int32_t i = start; i < numOfRows + pInput->startRowIndex; ++i) {
20,934,899✔
1794
        if (pCol->hasNull && colDataIsNull_f(pCol, i)) {
20,628,680✔
1795
          continue;
64,640✔
1796
        }
1797

1798
        numOfElem++;
20,564,040✔
1799
        LEASTSQR_CAL(param, x, plist, i, pInfo->stepVal);
20,564,040✔
1800
      }
1801
      break;
306,219✔
1802
    }
1803

1804
    case TSDB_DATA_TYPE_UTINYINT: {
19,592✔
1805
      uint8_t* plist = (uint8_t*)pCol->pData;
19,592✔
1806
      for (int32_t i = start; i < numOfRows + pInput->startRowIndex; ++i) {
20,303,272✔
1807
        if (pCol->hasNull && colDataIsNull_f(pCol, i)) {
20,283,680✔
1808
          continue;
11,440✔
1809
        }
1810
        numOfElem++;
20,272,240✔
1811
        LEASTSQR_CAL(param, x, plist, i, pInfo->stepVal);
20,272,240✔
1812
      }
1813
      break;
19,592✔
1814
    }
1815
    case TSDB_DATA_TYPE_USMALLINT: {
19,592✔
1816
      uint16_t* plist = (uint16_t*)pCol->pData;
19,592✔
1817
      for (int32_t i = start; i < numOfRows + pInput->startRowIndex; ++i) {
20,303,272✔
1818
        if (pCol->hasNull && colDataIsNull_f(pCol, i)) {
20,283,680✔
1819
          continue;
10,400✔
1820
        }
1821

1822
        numOfElem++;
20,273,280✔
1823
        LEASTSQR_CAL(param, x, plist, i, pInfo->stepVal);
20,273,280✔
1824
      }
1825
      break;
19,592✔
1826
    }
1827

1828
    case TSDB_DATA_TYPE_UINT: {
19,592✔
1829
      uint32_t* plist = (uint32_t*)pCol->pData;
19,592✔
1830
      for (int32_t i = start; i < numOfRows + pInput->startRowIndex; ++i) {
20,303,272✔
1831
        if (pCol->hasNull && colDataIsNull_f(pCol, i)) {
20,283,680✔
1832
          continue;
10,400✔
1833
        }
1834

1835
        numOfElem++;
20,273,280✔
1836
        LEASTSQR_CAL(param, x, plist, i, pInfo->stepVal);
20,273,280✔
1837
      }
1838
      break;
19,592✔
1839
    }
1840

1841
    case TSDB_DATA_TYPE_UBIGINT: {
19,592✔
1842
      uint64_t* plist = (uint64_t*)pCol->pData;
19,592✔
1843
      for (int32_t i = start; i < numOfRows + pInput->startRowIndex; ++i) {
20,303,272✔
1844
        if (pCol->hasNull && colDataIsNull_f(pCol, i)) {
20,283,680✔
1845
          continue;
10,400✔
1846
        }
1847

1848
        numOfElem++;
20,273,280✔
1849
        LEASTSQR_CAL(param, x, plist, i, pInfo->stepVal);
20,273,280✔
1850
      }
1851
      break;
19,592✔
1852
    }
1853

1854
    case TSDB_DATA_TYPE_FLOAT: {
1,488,536✔
1855
      float* plist = (float*)pCol->pData;
1,488,536✔
1856
      for (int32_t i = start; i < numOfRows + pInput->startRowIndex; ++i) {
104,290,012✔
1857
        if (pCol->hasNull && colDataIsNull_f(pCol, i)) {
102,799,092✔
1858
          continue;
64,640✔
1859
        }
1860

1861
        numOfElem++;
102,733,260✔
1862
        LEASTSQR_CAL(param, x, plist, i, pInfo->stepVal);
102,733,260✔
1863
      }
1864
      break;
1,489,728✔
1865
    }
1866

1867
    case TSDB_DATA_TYPE_DOUBLE: {
418,972✔
1868
      double* plist = (double*)pCol->pData;
418,972✔
1869
      for (int32_t i = start; i < numOfRows + pInput->startRowIndex; ++i) {
21,551,312✔
1870
        if (pCol->hasNull && colDataIsNull_f(pCol, i)) {
21,132,340✔
1871
          continue;
178,740✔
1872
        }
1873

1874
        numOfElem++;
20,953,600✔
1875
        LEASTSQR_CAL(param, x, plist, i, pInfo->stepVal);
20,953,600✔
1876
      }
1877
      break;
418,972✔
1878
    }
1879
    case TSDB_DATA_TYPE_NULL: {
×
1880
      GET_RES_INFO(pCtx)->isNullRes = 1;
×
1881
      numOfElem = 1;
×
1882
      break;
×
1883
    }
1884

1885
    default:
×
1886
      break;
×
1887
  }
1888

1889
  pInfo->startVal = x;
6,038,962✔
1890
  pInfo->num += numOfElem;
6,039,558✔
1891

1892
  SET_VAL(GET_RES_INFO(pCtx), numOfElem, 1);
6,038,366✔
1893

1894
  return TSDB_CODE_SUCCESS;
6,039,558✔
1895
}
1896

1897
int32_t leastSQRFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
5,078,412✔
1898
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
5,078,412✔
1899
  SLeastSQRInfo*       pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
5,078,412✔
1900
  int32_t              slotId = pCtx->pExpr->base.resSchema.slotId;
5,077,816✔
1901
  SColumnInfoData*     pCol = taosArrayGet(pBlock->pDataBlock, slotId);
5,078,412✔
1902

1903
  if (NULL == pCol) {
5,078,412✔
1904
    return TSDB_CODE_OUT_OF_RANGE;
×
1905
  }
1906
  int32_t currentRow = pBlock->info.rows;
5,078,412✔
1907

1908
  if (0 == pInfo->num) {
5,077,816✔
1909
    colDataSetNULL(pCol, currentRow);
3,411,202✔
1910
    return TSDB_CODE_SUCCESS;
3,411,798✔
1911
  }
1912

1913
  double(*param)[3] = pInfo->matrix;
1,666,614✔
1914

1915
  param[1][1] = (double)pInfo->num;
1,666,614✔
1916
  param[1][0] = param[0][1];
1,666,614✔
1917

1918
  double param00 = param[0][0] - param[1][0] * (param[0][1] / param[1][1]);
1,666,614✔
1919
  double param02 = param[0][2] - param[1][2] * (param[0][1] / param[1][1]);
1,666,614✔
1920

1921
  if (0 == param00) {
1,666,614✔
1922
    colDataSetNULL(pCol, currentRow);
949,286✔
1923
    return TSDB_CODE_SUCCESS;
949,286✔
1924
  }
1925

1926
  // param[0][1] = 0;
1927
  double param12 = param[1][2] - param02 * (param[1][0] / param00);
717,328✔
1928
  // param[1][0] = 0;
1929
  param02 /= param00;
717,328✔
1930

1931
  param12 /= param[1][1];
717,328✔
1932

1933
  char buf[LEASTSQUARES_BUFF_LENGTH] = {0};
717,328✔
1934
  char slopBuf[64] = {0};
717,328✔
1935
  char interceptBuf[64] = {0};
717,328✔
1936
  int  n = snprintf(slopBuf, 64, "%.6lf", param02);
717,328✔
1937
  if (n > LEASTSQUARES_DOUBLE_ITEM_LENGTH) {
717,328✔
1938
    (void)snprintf(slopBuf, 64, "%." DOUBLE_PRECISION_DIGITS, param02);
7,167✔
1939
  }
1940
  n = snprintf(interceptBuf, 64, "%.6lf", param12);
717,328✔
1941
  if (n > LEASTSQUARES_DOUBLE_ITEM_LENGTH) {
717,328✔
1942
    (void)snprintf(interceptBuf, 64, "%." DOUBLE_PRECISION_DIGITS, param12);
8,791✔
1943
  }
1944
  size_t len =
717,328✔
1945
      snprintf(varDataVal(buf), sizeof(buf) - VARSTR_HEADER_SIZE, "{slop:%s, intercept:%s}", slopBuf, interceptBuf);
717,328✔
1946
  varDataSetLen(buf, len);
717,328✔
1947

1948
  int32_t code = colDataSetVal(pCol, currentRow, buf, pResInfo->isNullRes);
717,328✔
1949

1950
  return code;
717,328✔
1951
}
1952

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

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

1975
bool getPercentileFuncEnv(SFunctionNode* pFunc, SFuncExecEnv* pEnv) {
100,131✔
1976
  pEnv->calcMemSize = sizeof(SPercentileInfo);
100,131✔
1977
  return true;
100,131✔
1978
}
1979

1980
int32_t percentileFunctionSetup(SqlFunctionCtx* pCtx, SResultRowEntryInfo* pResultInfo) {
441,792✔
1981
  if (pResultInfo->initialized) {
441,792✔
1982
    return TSDB_CODE_SUCCESS;
×
1983
  }
1984
  if (TSDB_CODE_SUCCESS != functionSetup(pCtx, pResultInfo)) {
441,792✔
1985
    return TSDB_CODE_FUNC_SETUP_ERROR;
×
1986
  }
1987

1988
  // in the first round, get the min-max value of all involved data
1989
  SPercentileInfo* pInfo = GET_ROWCELL_INTERBUF(pResultInfo);
441,792✔
1990
  SET_DOUBLE_VAL(&pInfo->minval, DBL_MAX);
441,792✔
1991
  SET_DOUBLE_VAL(&pInfo->maxval, -DBL_MAX);
441,792✔
1992
  pInfo->numOfElems = 0;
441,792✔
1993

1994
  return TSDB_CODE_SUCCESS;
441,792✔
1995
}
1996

1997
void percentileFunctionCleanupExt(SqlFunctionCtx* pCtx) {
100,131✔
1998
  if (pCtx == NULL || GET_RES_INFO(pCtx) == NULL || GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx)) == NULL) {
100,131✔
1999
    return;
×
2000
  }
2001
  SPercentileInfo* pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
100,131✔
2002
  if (pInfo->pMemBucket != NULL) {
100,131✔
2003
    tMemBucketDestroy(&(pInfo->pMemBucket));
×
2004
    pInfo->pMemBucket = NULL;
×
2005
  }
2006
}
2007

2008
int32_t percentileFunction(SqlFunctionCtx* pCtx) {
2,038,868✔
2009
  int32_t              code = TSDB_CODE_SUCCESS;
2,038,868✔
2010
  int32_t              numOfElems = 0;
2,038,868✔
2011
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
2,038,868✔
2012

2013
  SInputColumnInfoData* pInput = &pCtx->input;
2,038,868✔
2014
  SColumnDataAgg*       pAgg = pInput->pColumnDataAgg[0];
2,038,868✔
2015

2016
  SColumnInfoData* pCol = pInput->pData[0];
2,038,868✔
2017
  int32_t          type = pCol->info.type;
2,038,868✔
2018

2019
  SPercentileInfo* pInfo = GET_ROWCELL_INTERBUF(pResInfo);
2,038,868✔
2020
  if (pCtx->scanFlag == MAIN_SCAN && pInfo->stage == 0) {
2,038,868✔
2021
    pInfo->stage += 1;
441,792✔
2022

2023
    // all data are null, set it completed
2024
    if (pInfo->numOfElems == 0) {
441,792✔
2025
      pResInfo->complete = true;
163,143✔
2026
      return TSDB_CODE_SUCCESS;
163,143✔
2027
    } else {
2028
      code = tMemBucketCreate(pCol->info.bytes, type, typeGetTypeModFromColInfo(&pCol->info), pInfo->minval,
278,649✔
2029
                              pInfo->maxval, pCtx->hasWindowOrGroup, &pInfo->pMemBucket, pInfo->numOfElems);
278,649✔
2030
      if (TSDB_CODE_SUCCESS != code) {
278,649✔
2031
        return code;
×
2032
      }
2033
    }
2034
  }
2035

2036
  // the first stage, only acquire the min/max value
2037
  if (pInfo->stage == 0) {
1,875,725✔
2038
    if (pCtx->input.colDataSMAIsSet) {
1,022,776✔
2039
      double tmin = 0.0, tmax = 0.0;
×
2040
      if (IS_SIGNED_NUMERIC_TYPE(type)) {
×
2041
        tmin = (double)GET_INT64_VAL(&pAgg->min);
×
2042
        tmax = (double)GET_INT64_VAL(&pAgg->max);
×
2043
      } else if (IS_FLOAT_TYPE(type)) {
×
2044
        tmin = GET_DOUBLE_VAL(&pAgg->min);
×
2045
        tmax = GET_DOUBLE_VAL(&pAgg->max);
×
2046
      } else if (IS_UNSIGNED_NUMERIC_TYPE(type)) {
×
2047
        tmin = (double)GET_UINT64_VAL(&pAgg->min);
×
2048
        tmax = (double)GET_UINT64_VAL(&pAgg->max);
×
2049
      }
2050

2051
      if (GET_DOUBLE_VAL(&pInfo->minval) > tmin) {
×
2052
        SET_DOUBLE_VAL(&pInfo->minval, tmin);
×
2053
      }
2054

2055
      if (GET_DOUBLE_VAL(&pInfo->maxval) < tmax) {
×
2056
        SET_DOUBLE_VAL(&pInfo->maxval, tmax);
×
2057
      }
2058

2059
      pInfo->numOfElems += (pInput->numOfRows - pAgg->numOfNull);
×
2060
    } else {
2061
      // check the valid data one by one
2062
      int32_t start = pInput->startRowIndex;
1,022,776✔
2063
      for (int32_t i = start; i < pInput->numOfRows + start; ++i) {
21,562,080✔
2064
        if (colDataIsNull_f(pCol, i)) {
20,539,304✔
2065
          continue;
228,200✔
2066
        }
2067

2068
        char* data = colDataGetData(pCol, i);
20,311,104✔
2069

2070
        double v = 0;
20,311,104✔
2071
        GET_TYPED_DATA(v, double, type, data, typeGetTypeModFromColInfo(&pCol->info));
20,311,104✔
2072
        if (v < GET_DOUBLE_VAL(&pInfo->minval)) {
20,311,104✔
2073
          SET_DOUBLE_VAL(&pInfo->minval, v);
309,190✔
2074
        }
2075

2076
        if (v > GET_DOUBLE_VAL(&pInfo->maxval)) {
20,311,104✔
2077
          SET_DOUBLE_VAL(&pInfo->maxval, v);
16,262,286✔
2078
        }
2079

2080
        pInfo->numOfElems += 1;
20,311,104✔
2081
      }
2082
    }
2083
  } else {
2084
    // the second stage, calculate the true percentile value
2085
    int32_t start = pInput->startRowIndex;
852,949✔
2086
    for (int32_t i = start; i < pInput->numOfRows + start; ++i) {
21,164,053✔
2087
      if (colDataIsNull_f(pCol, i)) {
20,311,104✔
2088
        continue;
×
2089
      }
2090

2091
      char* data = colDataGetData(pCol, i);
20,311,104✔
2092
      numOfElems += 1;
20,311,104✔
2093
      code = tMemBucketPut(pInfo->pMemBucket, data, 1);
20,311,104✔
2094
      if (code != TSDB_CODE_SUCCESS) {
20,311,104✔
2095
        tMemBucketDestroy(&(pInfo->pMemBucket));
×
2096
        return code;
×
2097
      }
2098
    }
2099

2100
    SET_VAL(pResInfo, numOfElems, 1);
852,949✔
2101
  }
2102

2103
  pCtx->needCleanup = true;
1,875,725✔
2104
  return TSDB_CODE_SUCCESS;
1,875,725✔
2105
}
2106

2107
int32_t percentileFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
441,792✔
2108
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
441,792✔
2109
  SPercentileInfo*     ppInfo = (SPercentileInfo*)GET_ROWCELL_INTERBUF(pResInfo);
441,792✔
2110

2111
  int32_t code = 0;
441,792✔
2112
  double  v = 0;
441,792✔
2113

2114
  tMemBucket** pMemBucket = &ppInfo->pMemBucket;
441,792✔
2115
  if ((*pMemBucket) != NULL && (*pMemBucket)->total > 0) {  // check for null
441,792✔
2116
    if (pCtx->numOfParams > 2) {
278,649✔
2117
      char buf[3200] = {0};
3,102✔
2118
      // max length of double num is 317, e.g. use %.6lf to print -1.0e+308, consider the comma and bracket, 3200 is
2119
      // enough.
2120
      size_t len = 1;
3,102✔
2121

2122
      varDataVal(buf)[0] = '[';
3,102✔
2123
      for (int32_t i = 1; i < pCtx->numOfParams; ++i) {
34,122✔
2124
        SVariant* pVal = &pCtx->param[i].param;
31,020✔
2125

2126
        GET_TYPED_DATA(v, double, pVal->nType, &pVal->i, typeGetTypeModFromCol(pCtx->param[i].pCol));
31,020✔
2127

2128
        code = getPercentile((*pMemBucket), v, &ppInfo->result);
31,020✔
2129
        if (code != TSDB_CODE_SUCCESS) {
31,020✔
2130
          goto _fin_error;
×
2131
        }
2132

2133
        if (i == pCtx->numOfParams - 1) {
31,020✔
2134
          len += snprintf(varDataVal(buf) + len, sizeof(buf) - VARSTR_HEADER_SIZE - len, "%.6lf]", ppInfo->result);
3,102✔
2135
        } else {
2136
          len += snprintf(varDataVal(buf) + len, sizeof(buf) - VARSTR_HEADER_SIZE - len, "%.6lf, ", ppInfo->result);
27,918✔
2137
        }
2138
      }
2139

2140
      int32_t          slotId = pCtx->pExpr->base.resSchema.slotId;
3,102✔
2141
      SColumnInfoData* pCol = taosArrayGet(pBlock->pDataBlock, slotId);
3,102✔
2142
      if (NULL == pCol) {
3,102✔
2143
        code = terrno;
×
2144
        goto _fin_error;
×
2145
      }
2146

2147
      varDataSetLen(buf, len);
3,102✔
2148
      code = colDataSetVal(pCol, pBlock->info.rows, buf, false);
3,102✔
2149
      if (code != TSDB_CODE_SUCCESS) {
3,102✔
2150
        goto _fin_error;
×
2151
      }
2152

2153
      tMemBucketDestroy(pMemBucket);
3,102✔
2154
      return TSDB_CODE_SUCCESS;
3,102✔
2155
    } else {
2156
      SVariant* pVal = &pCtx->param[1].param;
275,547✔
2157

2158
      GET_TYPED_DATA(v, double, pVal->nType, &pVal->i, typeGetTypeModFromCol(pCtx->param[1].pCol));
275,547✔
2159

2160
      code = getPercentile((*pMemBucket), v, &ppInfo->result);
275,547✔
2161
      if (code != TSDB_CODE_SUCCESS) {
275,547✔
2162
        goto _fin_error;
×
2163
      }
2164

2165
      tMemBucketDestroy(pMemBucket);
275,547✔
2166
      return functionFinalize(pCtx, pBlock);
275,547✔
2167
    }
2168
  } else {
2169
    return functionFinalize(pCtx, pBlock);
163,143✔
2170
  }
2171

2172
_fin_error:
×
2173

2174
  tMemBucketDestroy(pMemBucket);
×
2175
  return code;
×
2176
}
2177

2178
bool getApercentileFuncEnv(SFunctionNode* pFunc, SFuncExecEnv* pEnv) {
3,697,368✔
2179
  int32_t bytesHist =
3,697,368✔
2180
      (int32_t)(sizeof(SAPercentileInfo) + sizeof(SHistogramInfo) + sizeof(SHistBin) * (MAX_HISTOGRAM_BIN + 1));
2181
  int32_t bytesDigest = (int32_t)(sizeof(SAPercentileInfo) + TDIGEST_SIZE(COMPRESSION));
3,697,368✔
2182
  pEnv->calcMemSize = TMAX(bytesHist, bytesDigest);
3,697,368✔
2183
  return true;
3,697,894✔
2184
}
2185

2186
int32_t getApercentileMaxSize() {
420,053✔
2187
  int32_t bytesHist =
420,053✔
2188
      (int32_t)(sizeof(SAPercentileInfo) + sizeof(SHistogramInfo) + sizeof(SHistBin) * (MAX_HISTOGRAM_BIN + 1));
2189
  int32_t bytesDigest = (int32_t)(sizeof(SAPercentileInfo) + TDIGEST_SIZE(COMPRESSION));
420,053✔
2190
  return TMAX(bytesHist, bytesDigest);
420,053✔
2191
}
2192

2193
static int8_t getApercentileAlgo(char* algoStr) {
3,346,214✔
2194
  int8_t algoType;
2195
  if (strcasecmp(algoStr, "default") == 0) {
3,346,214✔
2196
    algoType = APERCT_ALGO_DEFAULT;
1,672,450✔
2197
  } else if (strcasecmp(algoStr, "t-digest") == 0) {
1,673,764✔
2198
    algoType = APERCT_ALGO_TDIGEST;
1,674,360✔
2199
  } else {
2200
    algoType = APERCT_ALGO_UNKNOWN;
×
2201
  }
2202

2203
  return algoType;
3,346,214✔
2204
}
2205

2206
static void buildHistogramInfo(SAPercentileInfo* pInfo) {
254,009,712✔
2207
  pInfo->pHisto = (SHistogramInfo*)((char*)pInfo + sizeof(SAPercentileInfo));
254,009,712✔
2208
  pInfo->pHisto->elems = (SHistBin*)((char*)pInfo->pHisto + sizeof(SHistogramInfo));
254,012,188✔
2209
}
254,014,494✔
2210

2211
static void buildTDigestInfo(SAPercentileInfo* pInfo) {
3,364,425✔
2212
  pInfo->pTDigest = (TDigest*)((char*)pInfo + sizeof(SAPercentileInfo));
3,364,425✔
2213
}
3,367,405✔
2214

2215
int32_t apercentileFunctionSetup(SqlFunctionCtx* pCtx, SResultRowEntryInfo* pResultInfo) {
83,733,913✔
2216
  if (pResultInfo->initialized) {
83,733,913✔
2217
    return TSDB_CODE_SUCCESS;
×
2218
  }
2219
  if (TSDB_CODE_SUCCESS != functionSetup(pCtx, pResultInfo)) {
83,735,105✔
2220
    return TSDB_CODE_FUNC_SETUP_ERROR;
×
2221
  }
2222

2223
  SAPercentileInfo* pInfo = GET_ROWCELL_INTERBUF(pResultInfo);
83,735,662✔
2224

2225
  SVariant* pVal = &pCtx->param[1].param;
83,735,662✔
2226
  pInfo->percent = 0;
83,735,662✔
2227
  GET_TYPED_DATA(pInfo->percent, double, pVal->nType, &pVal->i, typeGetTypeModFromCol(pCtx->param[1].pCol));
83,735,662✔
2228

2229
  if (pCtx->numOfParams == 2) {
83,735,581✔
2230
    pInfo->algo = APERCT_ALGO_DEFAULT;
80,387,660✔
2231
  } else if (pCtx->numOfParams == 3) {
3,346,810✔
2232
    pInfo->algo = getApercentileAlgo(varDataVal(pCtx->param[2].param.pz));
3,349,194✔
2233
    if (pInfo->algo == APERCT_ALGO_UNKNOWN) {
3,348,598✔
2234
      return TSDB_CODE_FUNC_FUNTION_PARA_VALUE;
×
2235
    }
2236
  }
2237

2238
  char* tmp = (char*)pInfo + sizeof(SAPercentileInfo);
83,730,933✔
2239
  if (pInfo->algo == APERCT_ALGO_TDIGEST) {
83,733,317✔
2240
    pInfo->pTDigest = tdigestNewFrom(tmp, COMPRESSION);
1,673,764✔
2241
  } else {
2242
    buildHistogramInfo(pInfo);
82,057,208✔
2243
    pInfo->pHisto = tHistogramCreateFrom(tmp, MAX_HISTOGRAM_BIN);
82,059,433✔
2244
    qDebug("%s set up histogram, numOfElems:%" PRId64 ", numOfEntry:%d, pHisto:%p, elems:%p", __FUNCTION__,
82,060,706✔
2245
           pInfo->pHisto->numOfElems, pInfo->pHisto->numOfEntries, pInfo->pHisto, pInfo->pHisto->elems);
2246
  }
2247

2248
  return TSDB_CODE_SUCCESS;
83,735,066✔
2249
}
2250

2251
int32_t apercentileFunction(SqlFunctionCtx* pCtx) {
94,398,869✔
2252
  int32_t               numOfElems = 0;
94,398,869✔
2253
  SResultRowEntryInfo*  pResInfo = GET_RES_INFO(pCtx);
94,398,869✔
2254
  SInputColumnInfoData* pInput = &pCtx->input;
94,400,142✔
2255

2256
  SColumnInfoData* pCol = pInput->pData[0];
94,402,022✔
2257
  int32_t          type = pCol->info.type;
94,400,749✔
2258

2259
  SAPercentileInfo* pInfo = GET_ROWCELL_INTERBUF(pResInfo);
94,400,234✔
2260

2261
  int32_t start = pInput->startRowIndex;
94,402,618✔
2262
  if (pInfo->algo == APERCT_ALGO_TDIGEST) {
94,401,426✔
2263
    buildTDigestInfo(pInfo);
1,675,031✔
2264
    tdigestAutoFill(pInfo->pTDigest, COMPRESSION);
1,675,627✔
2265
    for (int32_t i = start; i < pInput->numOfRows + start; ++i) {
87,009,872✔
2266
      if (colDataIsNull_f(pCol, i)) {
85,337,821✔
2267
        continue;
43,784,513✔
2268
      }
2269
      numOfElems += 1;
41,547,348✔
2270
      char* data = colDataGetData(pCol, i);
41,547,348✔
2271

2272
      double  v = 0;  // value
41,547,944✔
2273
      int64_t w = 1;  // weigth
41,547,944✔
2274
      GET_TYPED_DATA(v, double, type, data, typeGetTypeModFromColInfo(&pCol->info));
41,547,944✔
2275
      int32_t code = tdigestAdd(pInfo->pTDigest, v, w);
41,547,944✔
2276
      if (code != TSDB_CODE_SUCCESS) {
41,549,732✔
2277
        return code;
×
2278
      }
2279
    }
2280
  } else {
2281
    // might be a race condition here that pHisto can be overwritten or setup function
2282
    // has not been called, need to relink the buffer pHisto points to.
2283
    buildHistogramInfo(pInfo);
92,726,314✔
2284
    qDebug("%s before add %d elements into histogram, total:%" PRId64 ", numOfEntry:%d, pHisto:%p, elems: %p",
92,726,991✔
2285
           __FUNCTION__, numOfElems, pInfo->pHisto->numOfElems, pInfo->pHisto->numOfEntries, pInfo->pHisto,
2286
           pInfo->pHisto->elems);
2287
    for (int32_t i = start; i < pInput->numOfRows + start; ++i) {
2,147,483,647✔
2288
      if (colDataIsNull_f(pCol, i)) {
2,147,483,647✔
2289
        continue;
1,641,279,006✔
2290
      }
2291
      numOfElems += 1;
1,018,775,865✔
2292
      char* data = colDataGetData(pCol, i);
1,018,775,865✔
2293

2294
      double v = 0;
1,019,337,324✔
2295
      GET_TYPED_DATA(v, double, type, data, typeGetTypeModFromColInfo(&pCol->info));
1,019,337,324✔
2296
      int32_t code = tHistogramAdd(&pInfo->pHisto, v);
1,019,337,911✔
2297
      if (code != TSDB_CODE_SUCCESS) {
1,016,344,824✔
2298
        return code;
×
2299
      }
2300
    }
2301

2302
    qDebug("%s after add %d elements into histogram, total:%" PRId64 ", numOfEntry:%d, pHisto:%p, elems: %p",
92,725,757✔
2303
           __FUNCTION__, numOfElems, pInfo->pHisto->numOfElems, pInfo->pHisto->numOfEntries, pInfo->pHisto,
2304
           pInfo->pHisto->elems);
2305
  }
2306

2307
  SET_VAL(pResInfo, numOfElems, 1);
94,401,345✔
2308
  return TSDB_CODE_SUCCESS;
94,401,345✔
2309
}
2310

2311
static int32_t apercentileTransferInfo(SAPercentileInfo* pInput, SAPercentileInfo* pOutput, bool* hasRes) {
269,660✔
2312
  pOutput->percent = pInput->percent;
269,660✔
2313
  pOutput->algo = pInput->algo;
269,660✔
2314
  if (pOutput->algo == APERCT_ALGO_TDIGEST) {
269,660✔
2315
    buildTDigestInfo(pInput);
16,151✔
2316
    tdigestAutoFill(pInput->pTDigest, COMPRESSION);
16,151✔
2317

2318
    if (pInput->pTDigest->num_centroids == 0 && pInput->pTDigest->num_buffered_pts == 0) {
16,151✔
2319
      return TSDB_CODE_SUCCESS;
521✔
2320
    }
2321

2322
    if (hasRes) {
15,630✔
2323
      *hasRes = true;
15,630✔
2324
    }
2325

2326
    buildTDigestInfo(pOutput);
15,630✔
2327
    TDigest* pTDigest = pOutput->pTDigest;
15,630✔
2328
    tdigestAutoFill(pTDigest, COMPRESSION);
15,630✔
2329

2330
    if (pTDigest->num_centroids <= 0 && pTDigest->num_buffered_pts == 0) {
15,630✔
2331
      (void)memcpy(pTDigest, pInput->pTDigest, (size_t)TDIGEST_SIZE(COMPRESSION));
15,630✔
2332
      tdigestAutoFill(pTDigest, COMPRESSION);
15,630✔
2333
    } else {
2334
      int32_t code = tdigestMerge(pTDigest, pInput->pTDigest);
×
2335
      if (TSDB_CODE_SUCCESS != code) {
×
2336
        return code;
×
2337
      }
2338
    }
2339
  } else {
2340
    buildHistogramInfo(pInput);
253,509✔
2341
    if (pInput->pHisto->numOfElems <= 0) {
253,509✔
2342
      return TSDB_CODE_SUCCESS;
114,146✔
2343
    }
2344

2345
    if (hasRes) {
139,363✔
2346
      *hasRes = true;
139,363✔
2347
    }
2348

2349
    buildHistogramInfo(pOutput);
139,363✔
2350
    SHistogramInfo* pHisto = pOutput->pHisto;
139,363✔
2351

2352
    if (pHisto->numOfElems <= 0) {
139,363✔
2353
      (void)memcpy(pHisto, pInput->pHisto, sizeof(SHistogramInfo) + sizeof(SHistBin) * (MAX_HISTOGRAM_BIN + 1));
122,376✔
2354
      pHisto->elems = (SHistBin*)((char*)pHisto + sizeof(SHistogramInfo));
122,376✔
2355

2356
      qDebug("%s merge histo, total:%" PRId64 ", entry:%d, %p", __FUNCTION__, pHisto->numOfElems, pHisto->numOfEntries,
122,376✔
2357
             pHisto);
2358
    } else {
2359
      pHisto->elems = (SHistBin*)((char*)pHisto + sizeof(SHistogramInfo));
16,987✔
2360
      qDebug("%s input histogram, elem:%" PRId64 ", entry:%d, %p", __FUNCTION__, pHisto->numOfElems,
16,987✔
2361
             pHisto->numOfEntries, pInput->pHisto);
2362

2363
      SHistogramInfo* pRes = NULL;
16,987✔
2364
      int32_t         code = tHistogramMerge(pHisto, pInput->pHisto, MAX_HISTOGRAM_BIN, &pRes);
16,987✔
2365
      if (TSDB_CODE_SUCCESS != code) {
16,987✔
2366
        tHistogramDestroy(&pRes);
×
2367
        return code;
×
2368
      }
2369
      (void)memcpy(pHisto, pRes, sizeof(SHistogramInfo) + sizeof(SHistBin) * MAX_HISTOGRAM_BIN);
16,987✔
2370
      pHisto->elems = (SHistBin*)((char*)pHisto + sizeof(SHistogramInfo));
16,987✔
2371

2372
      qDebug("%s merge histo, total:%" PRId64 ", entry:%d, %p", __FUNCTION__, pHisto->numOfElems, pHisto->numOfEntries,
16,987✔
2373
             pHisto);
2374
      tHistogramDestroy(&pRes);
16,987✔
2375
    }
2376
  }
2377
  return TSDB_CODE_SUCCESS;
154,993✔
2378
}
2379

2380
int32_t apercentileFunctionMerge(SqlFunctionCtx* pCtx) {
264,979✔
2381
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
264,979✔
2382

2383
  SInputColumnInfoData* pInput = &pCtx->input;
264,979✔
2384

2385
  SColumnInfoData* pCol = pInput->pData[0];
264,979✔
2386
  if (pCol->info.type != TSDB_DATA_TYPE_BINARY) {
264,979✔
2387
    return TSDB_CODE_FUNC_FUNTION_PARA_TYPE;
×
2388
  }
2389

2390
  SAPercentileInfo* pInfo = GET_ROWCELL_INTERBUF(pResInfo);
264,979✔
2391

2392
  qDebug("%s total %" PRId64 " rows will merge, %p", __FUNCTION__, pInput->numOfRows, pInfo->pHisto);
264,979✔
2393

2394
  bool    hasRes = false;
264,979✔
2395
  int32_t start = pInput->startRowIndex;
264,979✔
2396
  for (int32_t i = start; i < start + pInput->numOfRows; ++i) {
534,639✔
2397
    char* data = colDataGetData(pCol, i);
269,660✔
2398

2399
    SAPercentileInfo* pInputInfo = (SAPercentileInfo*)varDataVal(data);
269,660✔
2400
    int32_t           code = apercentileTransferInfo(pInputInfo, pInfo, &hasRes);
269,660✔
2401
    if (TSDB_CODE_SUCCESS != code) {
269,660✔
2402
      return code;
×
2403
    }
2404
  }
2405

2406
  if (pInfo->algo != APERCT_ALGO_TDIGEST) {
264,979✔
2407
    buildHistogramInfo(pInfo);
248,828✔
2408
    qDebug("%s after merge, total:%" PRId64 ", numOfEntry:%d, %p", __FUNCTION__, pInfo->pHisto->numOfElems,
248,828✔
2409
           pInfo->pHisto->numOfEntries, pInfo->pHisto);
2410
  }
2411

2412
  SET_VAL(pResInfo, hasRes ? 1 : 0, 1);
264,979✔
2413
  return TSDB_CODE_SUCCESS;
264,979✔
2414
}
2415

2416
int32_t apercentileFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
80,245,771✔
2417
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
80,245,771✔
2418
  SAPercentileInfo*    pInfo = (SAPercentileInfo*)GET_ROWCELL_INTERBUF(pResInfo);
80,245,771✔
2419

2420
  if (pInfo->algo == APERCT_ALGO_TDIGEST) {
80,245,771✔
2421
    buildTDigestInfo(pInfo);
1,659,997✔
2422
    tdigestAutoFill(pInfo->pTDigest, COMPRESSION);
1,659,997✔
2423
    if (pInfo->pTDigest->size > 0) {
1,659,997✔
2424
      pInfo->result = tdigestQuantile(pInfo->pTDigest, pInfo->percent / 100);
1,659,997✔
2425
    } else {  // no need to free
2426
      // setNull(pCtx->pOutput, pCtx->outputType, pCtx->outputBytes);
2427
      return TSDB_CODE_SUCCESS;
×
2428
    }
2429
  } else {
2430
    buildHistogramInfo(pInfo);
78,584,582✔
2431
    if (pInfo->pHisto->numOfElems > 0) {
78,585,774✔
2432
      qDebug("%s get the final res, elements:%" PRId64 ", numOfEntry:%d, pHisto:%p, elems:%p", __FUNCTION__,
38,213,077✔
2433
             pInfo->pHisto->numOfElems, pInfo->pHisto->numOfEntries, pInfo->pHisto, pInfo->pHisto->elems);
2434

2435
      double  ratio[] = {pInfo->percent};
38,213,077✔
2436
      double* res = NULL;
38,213,077✔
2437
      int32_t code = tHistogramUniform(pInfo->pHisto, ratio, 1, &res);
38,213,077✔
2438
      if (TSDB_CODE_SUCCESS != code) {
38,213,077✔
2439
        taosMemoryFree(res);
×
2440
        return code;
×
2441
      }
2442
      pInfo->result = *res;
38,213,077✔
2443
      // memcpy(pCtx->pOutput, res, sizeof(double));
2444
      taosMemoryFree(res);
38,213,077✔
2445
    } else {  // no need to free
2446
      // setNull(pCtx->pOutput, pCtx->outputType, pCtx->outputBytes);
2447
      // return TSDB_CODE_SUCCESS;
2448
      qDebug("%s get the final res, elements:%" PRId64 ", numOfEntry:%d. result is null", __FUNCTION__,
40,371,505✔
2449
             pInfo->pHisto->numOfElems, pInfo->pHisto->numOfEntries);
2450
    }
2451
  }
2452

2453
  return functionFinalize(pCtx, pBlock);
80,244,579✔
2454
}
2455

2456
int32_t apercentilePartialFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
269,660✔
2457
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
269,660✔
2458
  SAPercentileInfo*    pInfo = (SAPercentileInfo*)GET_ROWCELL_INTERBUF(pResInfo);
269,660✔
2459

2460
  int32_t resultBytes = getApercentileMaxSize();
269,660✔
2461
  char*   res = taosMemoryCalloc(resultBytes + VARSTR_HEADER_SIZE, sizeof(char));
269,660✔
2462
  if (NULL == res) {
269,660✔
2463
    return terrno;
×
2464
  }
2465

2466
  if (pInfo->algo == APERCT_ALGO_TDIGEST) {
269,660✔
2467
    (void)memcpy(varDataVal(res), pInfo, resultBytes);
16,151✔
2468
    varDataSetLen(res, resultBytes);
16,151✔
2469
  } else {
2470
    (void)memcpy(varDataVal(res), pInfo, resultBytes);
253,509✔
2471
    varDataSetLen(res, resultBytes);
253,509✔
2472
  }
2473

2474
  int32_t          slotId = pCtx->pExpr->base.resSchema.slotId;
269,660✔
2475
  SColumnInfoData* pCol = taosArrayGet(pBlock->pDataBlock, slotId);
269,660✔
2476
  if (NULL == pCol) {
269,660✔
2477
    taosMemoryFree(res);
×
2478
    return TSDB_CODE_OUT_OF_RANGE;
×
2479
  }
2480

2481
  int32_t code = colDataSetVal(pCol, pBlock->info.rows, res, false);
269,660✔
2482

2483
  taosMemoryFree(res);
269,660✔
2484
  return code;
269,660✔
2485
}
2486

2487
int32_t apercentileCombine(SqlFunctionCtx* pDestCtx, SqlFunctionCtx* pSourceCtx) {
×
2488
  SResultRowEntryInfo* pDResInfo = GET_RES_INFO(pDestCtx);
×
2489
  SAPercentileInfo*    pDBuf = GET_ROWCELL_INTERBUF(pDResInfo);
×
2490

2491
  SResultRowEntryInfo* pSResInfo = GET_RES_INFO(pSourceCtx);
×
2492
  SAPercentileInfo*    pSBuf = GET_ROWCELL_INTERBUF(pSResInfo);
×
2493

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

2496
  int32_t code = apercentileTransferInfo(pSBuf, pDBuf, NULL);
×
2497
  if (TSDB_CODE_SUCCESS != code) {
×
2498
    return code;
×
2499
  }
2500
  pDResInfo->numOfRes = TMAX(pDResInfo->numOfRes, pSResInfo->numOfRes);
×
2501
  pDResInfo->isNullRes &= pSResInfo->isNullRes;
×
2502
  return TSDB_CODE_SUCCESS;
×
2503
}
2504

2505
// TODO: change this function when block data info pks changed
2506
static int32_t comparePkDataWithSValue(int8_t pkType, char* pkData, SValue* pVal, int32_t order) {
619,811✔
2507
  char numVal[8] = {0};
619,811✔
2508
  switch (pkType) {
619,811✔
2509
    case TSDB_DATA_TYPE_INT:
115,991✔
2510
      *(int32_t*)numVal = (int32_t)VALUE_GET_TRIVIAL_DATUM(pVal);
115,991✔
2511
      break;
115,991✔
2512
    case TSDB_DATA_TYPE_UINT:
106,300✔
2513
      *(uint32_t*)numVal = (uint32_t)VALUE_GET_TRIVIAL_DATUM(pVal);
106,300✔
2514
      break;
106,300✔
2515
    case TSDB_DATA_TYPE_BIGINT:
106,300✔
2516
      *(int64_t*)numVal = (int64_t)VALUE_GET_TRIVIAL_DATUM(pVal);
106,300✔
2517
      break;
106,300✔
2518
    case TSDB_DATA_TYPE_UBIGINT:
107,018✔
2519
      *(uint64_t*)numVal = (uint64_t)VALUE_GET_TRIVIAL_DATUM(pVal);
107,018✔
2520
      break;
107,018✔
2521
    default:
184,202✔
2522
      break;
184,202✔
2523
  }
2524
  char*         blockData = (IS_NUMERIC_TYPE(pkType)) ? (char*)numVal : (char*)pVal->pData;
619,811✔
2525
  __compar_fn_t fn = getKeyComparFunc(pkType, order);
619,811✔
2526
  return fn(pkData, blockData);
619,093✔
2527
}
2528

2529
EFuncDataRequired firstDynDataReq(void* pRes, SDataBlockInfo* pBlockInfo) {
2,147,483,647✔
2530
  SResultRowEntryInfo* pEntry = (SResultRowEntryInfo*)pRes;
2,147,483,647✔
2531

2532
  // not initialized yet, data is required
2533
  if (pEntry == NULL) {
2,147,483,647✔
2534
    return FUNC_DATA_REQUIRED_DATA_LOAD;
×
2535
  }
2536

2537
  SFirstLastRes* pResult = GET_ROWCELL_INTERBUF(pEntry);
2,147,483,647✔
2538
  if (pResult->hasResult) {
2,147,483,647✔
2539
    if (pResult->pkBytes > 0) {
2,147,483,647✔
2540
      pResult->pkData = pResult->buf + pResult->bytes;
1,054,815✔
2541
    } else {
2542
      pResult->pkData = NULL;
2,147,483,647✔
2543
    }
2544
    if (pResult->ts < pBlockInfo->window.skey) {
2,147,483,647✔
2545
      return FUNC_DATA_REQUIRED_NOT_LOAD;
3,678,038✔
2546
    } else if (pResult->ts == pBlockInfo->window.skey) {
2,147,483,647✔
2547
      if (NULL == pResult->pkData) {
2,147,483,647✔
2548
        return FUNC_DATA_REQUIRED_NOT_LOAD;
2,147,483,647✔
2549
      }
2550
      if (comparePkDataWithSValue(pResult->pkType, pResult->pkData, pBlockInfo->pks + 0, TSDB_ORDER_ASC) < 0) {
422,424✔
2551
        return FUNC_DATA_REQUIRED_NOT_LOAD;
90,654✔
2552
      }
2553
    }
2554
    return FUNC_DATA_REQUIRED_DATA_LOAD;
629,619✔
2555
  } else {
2556
    return FUNC_DATA_REQUIRED_DATA_LOAD;
2,413,555✔
2557
  }
2558
}
2559

2560
EFuncDataRequired lastDynDataReq(void* pRes, SDataBlockInfo* pBlockInfo) {
31,620,034✔
2561
  SResultRowEntryInfo* pEntry = (SResultRowEntryInfo*)pRes;
31,620,034✔
2562

2563
  // not initialized yet, data is required
2564
  if (pEntry == NULL) {
31,620,034✔
2565
    return FUNC_DATA_REQUIRED_DATA_LOAD;
×
2566
  }
2567

2568
  SFirstLastRes* pResult = GET_ROWCELL_INTERBUF(pEntry);
31,620,034✔
2569
  if (pResult->hasResult) {
31,622,208✔
2570
    if (pResult->pkBytes > 0) {
29,248,921✔
2571
      pResult->pkData = pResult->buf + pResult->bytes;
638,607✔
2572
    } else {
2573
      pResult->pkData = NULL;
28,610,361✔
2574
    }
2575
    if (pResult->ts > pBlockInfo->window.ekey) {
29,249,609✔
2576
      return FUNC_DATA_REQUIRED_NOT_LOAD;
8,622,174✔
2577
    } else if (pResult->ts == pBlockInfo->window.ekey && pResult->pkData) {
20,626,794✔
2578
      if (comparePkDataWithSValue(pResult->pkType, pResult->pkData, pBlockInfo->pks + 1, TSDB_ORDER_DESC) < 0) {
197,387✔
2579
        return FUNC_DATA_REQUIRED_NOT_LOAD;
69,070✔
2580
      }
2581
    }
2582
    return FUNC_DATA_REQUIRED_DATA_LOAD;
20,557,630✔
2583
  } else {
2584
    return FUNC_DATA_REQUIRED_DATA_LOAD;
2,373,517✔
2585
  }
2586
}
2587

2588
// TODO modify it to include primary key bytes
2589
int32_t getFirstLastInfoSize(int32_t resBytes, int32_t pkBytes) { return sizeof(SFirstLastRes) + resBytes + pkBytes; }
1,960,590,858✔
2590

2591
bool getFirstLastFuncEnv(SFunctionNode* pFunc, SFuncExecEnv* pEnv) {
64,647,389✔
2592
  SColumnNode* pNode = (SColumnNode*)nodesListGetNode(pFunc->pParameterList, 0);
64,647,389✔
2593
  // TODO: change SFunctionNode to add pk info
2594
  int32_t pkBytes = (pFunc->hasPk) ? pFunc->pkBytes : 0;
64,657,683✔
2595
  pEnv->calcMemSize = getFirstLastInfoSize(pNode->node.resType.bytes, pkBytes);
64,642,793✔
2596
  return true;
64,653,404✔
2597
}
2598

2599
bool getSelectivityFuncEnv(SFunctionNode* pFunc, SFuncExecEnv* pEnv) {
16,060,058✔
2600
  SColumnNode* pNode = (SColumnNode*)nodesListGetNode(pFunc->pParameterList, 0);
16,060,058✔
2601
  pEnv->calcMemSize = pNode->node.resType.bytes;
16,061,036✔
2602
  return true;
16,057,635✔
2603
}
2604

2605

2606
bool getHasNullFuncEnv(SFunctionNode* pFunc, SFuncExecEnv* pEnv) {
23,621,040✔
2607
  pEnv->calcMemSize = pFunc->node.resType.bytes;
23,621,040✔
2608
  return true;
23,621,040✔
2609
}
2610

2611
bool getGroupKeyFuncEnv(SFunctionNode* pFunc, SFuncExecEnv* pEnv) {
64,429,616✔
2612
  SColumnNode* pNode = (SColumnNode*)nodesListGetNode(pFunc->pParameterList, 0);
64,429,616✔
2613
  pEnv->calcMemSize = sizeof(SGroupKeyInfo) + pNode->node.resType.bytes;
64,431,010✔
2614
  return true;
64,426,595✔
2615
}
2616

2617
static FORCE_INLINE TSKEY getRowPTs(SColumnInfoData* pTsColInfo, int32_t rowIndex) {
2618
  if (pTsColInfo == NULL || pTsColInfo->pData == NULL) {
2,147,483,647✔
2619
    return 0;
×
2620
  }
2621

2622
  return *(TSKEY*)colDataGetData(pTsColInfo, rowIndex);
2,147,483,647✔
2623
}
2624

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

2633
  SFirstLastRes* pRes = GET_ROWCELL_INTERBUF(pResInfo);
2,147,483,647✔
2634
  pRes->nullTupleSaved = false;
2,147,483,647✔
2635
  pRes->nullTuplePos.pageId = -1;
2,147,483,647✔
2636
  return TSDB_CODE_SUCCESS;
2,147,483,647✔
2637
}
2638

2639
static int32_t prepareBuf(SqlFunctionCtx* pCtx) {
122,579,412✔
2640
  if (pCtx->subsidiaries.rowLen == 0) {
122,579,412✔
2641
    int32_t rowLen = 0;
5,208,350✔
2642
    for (int32_t j = 0; j < pCtx->subsidiaries.num; ++j) {
12,177,915✔
2643
      SqlFunctionCtx* pc = pCtx->subsidiaries.pCtx[j];
6,976,757✔
2644
      rowLen += pc->pExpr->base.resSchema.bytes;
6,970,559✔
2645
    }
2646

2647
    pCtx->subsidiaries.rowLen = rowLen + pCtx->subsidiaries.num * sizeof(bool);
5,204,984✔
2648
    pCtx->subsidiaries.buf = taosMemoryMalloc(pCtx->subsidiaries.rowLen);
5,211,875✔
2649
    if (NULL == pCtx->subsidiaries.buf) {
5,210,589✔
2650
      return terrno;
×
2651
    }
2652
  }
2653
  return TSDB_CODE_SUCCESS;
122,581,308✔
2654
}
2655

2656
static int32_t firstlastSaveTupleData(const SSDataBlock* pSrcBlock, int32_t rowIndex, SqlFunctionCtx* pCtx,
2,147,483,647✔
2657
                                      SFirstLastRes* pInfo, bool noElements) {
2658
  int32_t code = TSDB_CODE_SUCCESS;
2,147,483,647✔
2659

2660
  if (pCtx->subsidiaries.num <= 0) {
2,147,483,647✔
2661
    return TSDB_CODE_SUCCESS;
2,147,483,647✔
2662
  }
2663

2664
  if (!pInfo->hasResult) {
76,412,422✔
2665
    code = saveTupleData(pCtx, rowIndex, pSrcBlock, &pInfo->pos);
64,157,618✔
2666
  } else if (!noElements) {
12,257,685✔
2667
    code = updateTupleData(pCtx, rowIndex, pSrcBlock, &pInfo->pos);
12,242,724✔
2668
  } else {
2669
  }  // dothing
2670

2671
  return code;
76,416,625✔
2672
}
2673

2674
static int32_t doSaveCurrentVal(SqlFunctionCtx* pCtx, int32_t rowIndex, int64_t currentTs, char* pkData, int32_t type,
2,147,483,647✔
2675
                                char* pData) {
2676
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
2,147,483,647✔
2677
  SFirstLastRes*       pInfo = GET_ROWCELL_INTERBUF(pResInfo);
2,147,483,647✔
2678

2679
  if (IS_VAR_DATA_TYPE(type)) {
2,147,483,647✔
2680
    pInfo->bytes = calcStrBytesByType(type, pData);
2,147,483,647✔
2681
    // if (type == TSDB_DATA_TYPE_JSON) {
2682
    //   pInfo->bytes = getJsonValueLen(pData);
2683
    // } else {
2684
    //   pInfo->bytes = varDataTLen(pData);
2685
    // }
2686
  }
2687

2688
  (void)memcpy(pInfo->buf, pData, pInfo->bytes);
2,147,483,647✔
2689
  if (pkData != NULL) {
2,147,483,647✔
2690
    if (IS_VAR_DATA_TYPE(pInfo->pkType)) {
194,325,697✔
2691
      pInfo->pkBytes = calcStrBytesByType(pInfo->pkType, pkData);
64,741,383✔
2692
      // if (pInfo->pkType == TSDB_DATA_TYPE_JSON) {
2693
      //   pInfo->pkBytes = getJsonValueLen(pkData);
2694
      // } else {
2695
      //   pInfo->pkBytes = varDataTLen(pkData);
2696
      // }
2697
    }
2698
    (void)memcpy(pInfo->buf + pInfo->bytes, pkData, pInfo->pkBytes);
194,315,483✔
2699
    pInfo->pkData = pInfo->buf + pInfo->bytes;
194,328,483✔
2700
  }
2701

2702
  pInfo->ts = currentTs;
2,147,483,647✔
2703
  int32_t code = firstlastSaveTupleData(pCtx->pSrcBlock, rowIndex, pCtx, pInfo, false);
2,147,483,647✔
2704
  if (code != TSDB_CODE_SUCCESS) {
2,147,483,647✔
2705
    return code;
×
2706
  }
2707

2708
  pInfo->hasResult = true;
2,147,483,647✔
2709
  return TSDB_CODE_SUCCESS;
2,147,483,647✔
2710
}
2711

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

2717
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
2,147,483,647✔
2718
  SFirstLastRes*       pInfo = GET_ROWCELL_INTERBUF(pResInfo);
2,147,483,647✔
2719

2720
  SInputColumnInfoData* pInput = &pCtx->input;
2,147,483,647✔
2721
  SColumnInfoData*      pInputCol = pInput->pData[0];
2,147,483,647✔
2722

2723
  pInfo->bytes = pInputCol->info.bytes;
2,147,483,647✔
2724

2725
  if (IS_NULL_TYPE(pInputCol->info.type)) {
2,147,483,647✔
2726
    return TSDB_CODE_SUCCESS;
721,616✔
2727
  }
2728

2729
  SColumnInfoData* pkCol = pInput->pPrimaryKey;
2,147,483,647✔
2730
  pInfo->pkType = -1;
2,147,483,647✔
2731
  __compar_fn_t pkCompareFn = NULL;
2,147,483,647✔
2732
  if (pCtx->hasPrimaryKey) {
2,147,483,647✔
2733
    pInfo->pkType = pkCol->info.type;
53,035,375✔
2734
    pInfo->pkBytes = pkCol->info.bytes;
53,053,289✔
2735
    pkCompareFn = getKeyComparFunc(pInfo->pkType, TSDB_ORDER_ASC);
53,047,831✔
2736
  }
2737

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

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

2752
  TSKEY startKey = getRowPTs(pInput->pPTS, 0);
2,147,483,647✔
2753
  TSKEY endKey = getRowPTs(pInput->pPTS, pInput->totalRows - 1);
2,147,483,647✔
2754

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

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

2768
    for (int32_t i = pInput->startRowIndex; i < pInput->startRowIndex + pInput->numOfRows; ++i) {
2769
      if (pInputCol->hasNull && colDataIsNull(pInputCol, pInput->totalRows, i, pColAgg)) {
2770
        continue;
2771
      }
2772

2773
      numOfElems++;
2774

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

2791
    for (int32_t i = pInput->numOfRows + pInput->startRowIndex - 1; i >= pInput->startRowIndex; --i) {
2792
      if (pInputCol->hasNull && colDataIsNull(pInputCol, pInput->totalRows, i, pColAgg)) {
2793
        continue;
2794
      }
2795

2796
      numOfElems++;
2797

2798
      char* data = colDataGetData(pInputCol, i);
2799
      TSKEY cts = getRowPTs(pInput->pPTS, i);
2800

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

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

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

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

2847
int32_t lastFunction(SqlFunctionCtx* pCtx) {
2,147,483,647✔
2848
  int32_t numOfElems = 0;
2,147,483,647✔
2849

2850
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
2,147,483,647✔
2851
  SFirstLastRes*       pInfo = GET_ROWCELL_INTERBUF(pResInfo);
2,147,483,647✔
2852

2853
  SInputColumnInfoData* pInput = &pCtx->input;
2,147,483,647✔
2854
  SColumnInfoData*      pInputCol = pInput->pData[0];
2,147,483,647✔
2855

2856
  int32_t type = pInputCol->info.type;
2,147,483,647✔
2857
  int32_t bytes = pInputCol->info.bytes;
2,147,483,647✔
2858

2859
  if (IS_NULL_TYPE(type)) {
2,147,483,647✔
2860
    return TSDB_CODE_SUCCESS;
703,013✔
2861
  }
2862
  pInfo->bytes = bytes;
2,147,483,647✔
2863

2864
  SColumnInfoData* pkCol = pInput->pPrimaryKey;
2,147,483,647✔
2865
  pInfo->pkType = -1;
2,147,483,647✔
2866
  __compar_fn_t pkCompareFn = NULL;
2,147,483,647✔
2867
  if (pCtx->hasPrimaryKey) {
2,147,483,647✔
2868
    pInfo->pkType = pkCol->info.type;
53,114,446✔
2869
    pInfo->pkBytes = pkCol->info.bytes;
53,115,848✔
2870
    pkCompareFn = getKeyComparFunc(pInfo->pkType, TSDB_ORDER_DESC);
53,096,297✔
2871
  }
2872

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

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

2887
  TSKEY startKey = getRowPTs(pInput->pPTS, 0);
2,147,483,647✔
2888
  TSKEY endKey = getRowPTs(pInput->pPTS, pInput->totalRows - 1);
2,147,483,647✔
2889

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

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

2900
      numOfElems++;
2901

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

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

2916
      numOfElems++;
2917

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

2929
#if 0
2930
    for (int32_t i = pInput->startRowIndex; i < pInput->numOfRows + pInput->startRowIndex; ++i) {
2931
      if (pInputCol->hasNull && colDataIsNull(pInputCol, pInput->totalRows, i, pColAgg)) {
2932
        continue;
2933
      }
2934

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

2944
  // todo refactor
2945
  if (!pInputCol->hasNull && !pCtx->hasPrimaryKey) {
2,147,483,647✔
2946
    numOfElems = 1;
2,147,483,647✔
2947

2948
    int32_t round = pInput->numOfRows >> 2;
2,147,483,647✔
2949
    int32_t reminder = pInput->numOfRows & 0x03;
2,147,483,647✔
2950

2951
    for (int32_t i = pInput->startRowIndex, tick = 0; tick < round; i += 4, tick += 1) {
2,147,483,647✔
2952
      int64_t cts = pts[i];
539,942,969✔
2953
      int32_t chosen = i;
539,957,501✔
2954

2955
      if (cts < pts[i + 1]) {
539,957,501✔
2956
        cts = pts[i + 1];
151,745,689✔
2957
        chosen = i + 1;
151,745,689✔
2958
      }
2959

2960
      if (cts < pts[i + 2]) {
539,953,677✔
2961
        cts = pts[i + 2];
151,746,002✔
2962
        chosen = i + 2;
151,746,002✔
2963
      }
2964

2965
      if (cts < pts[i + 3]) {
539,948,884✔
2966
        cts = pts[i + 3];
151,744,216✔
2967
        chosen = i + 3;
151,744,216✔
2968
      }
2969

2970
      if (pResInfo->numOfRes == 0 || pInfo->ts < cts) {
539,951,905✔
2971
        char*   data = colDataGetData(pInputCol, chosen);
182,311,405✔
2972
        int32_t code = doSaveCurrentVal(pCtx, chosen, cts, NULL, type, data);
182,301,090✔
2973
        if (code != TSDB_CODE_SUCCESS) {
182,315,979✔
2974
          return code;
×
2975
        }
2976
        pResInfo->numOfRes = 1;
182,315,979✔
2977
      }
2978
    }
2979

2980
    for (int32_t i = pInput->startRowIndex + round * 4; i < pInput->startRowIndex + pInput->numOfRows; ++i) {
2,147,483,647✔
2981
      if (pResInfo->numOfRes == 0 || pInfo->ts < pts[i]) {
2,147,483,647✔
2982
        char*   data = colDataGetData(pInputCol, i);
1,006,971,840✔
2983
        int32_t code = doSaveCurrentVal(pCtx, i, pts[i], NULL, type, data);
1,002,338,531✔
2984
        if (code != TSDB_CODE_SUCCESS) {
1,002,233,325✔
2985
          return code;
×
2986
        }
2987
        pResInfo->numOfRes = 1;
1,002,233,325✔
2988
      }
2989
    }
2990
  } else {
2991
    int     from = -1;
2,147,483,647✔
2992
    int32_t i = -1;
2,147,483,647✔
2993
    while (funcInputGetNextRowIndex(pInput, from, false, &i, &from)) {
2,147,483,647✔
2994
      if (colDataIsNull(pInputCol, pInput->totalRows, i, pColAgg)) {
2,147,483,647✔
2995
        continue;
2,147,483,647✔
2996
      }
2997

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

3019
#endif
3020

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

3030
  return TSDB_CODE_SUCCESS;
2,147,483,647✔
3031
}
3032

3033
static bool firstLastTransferInfoImpl(SFirstLastRes* pInput, SFirstLastRes* pOutput, bool isFirst) {
1,510,892,547✔
3034
  if (!pInput->hasResult) {
1,510,892,547✔
3035
    return false;
×
3036
  }
3037
  __compar_fn_t pkCompareFn = NULL;
1,510,892,547✔
3038
  if (pInput->pkData) {
1,510,892,547✔
3039
    pkCompareFn = getKeyComparFunc(pInput->pkType, (isFirst) ? TSDB_ORDER_ASC : TSDB_ORDER_DESC);
2,206,711✔
3040
  }
3041
  if (pOutput->hasResult) {
1,510,893,627✔
3042
    if (isFirst) {
823,748,607✔
3043
      if (pInput->ts > pOutput->ts ||
720,435,008✔
3044
          (pInput->ts == pOutput->ts && pkCompareFn && pkCompareFn(pInput->pkData, pOutput->pkData) > 0)) {
719,444,810✔
3045
        return false;
990,198✔
3046
      }
3047
    } else {
3048
      if (pInput->ts < pOutput->ts ||
103,313,599✔
3049
          (pInput->ts == pOutput->ts && pkCompareFn && pkCompareFn(pInput->pkData, pOutput->pkData) > 0)) {
100,283,066✔
3050
        return false;
3,030,533✔
3051
      }
3052
    }
3053
  }
3054

3055
  pOutput->isNull = pInput->isNull;
1,506,873,166✔
3056
  pOutput->ts = pInput->ts;
1,506,873,166✔
3057
  pOutput->bytes = pInput->bytes;
1,506,873,436✔
3058
  pOutput->pkType = pInput->pkType;
1,506,874,246✔
3059

3060
  (void)memcpy(pOutput->buf, pInput->buf, pOutput->bytes);
1,506,873,166✔
3061
  if (pInput->pkData) {
1,506,872,626✔
3062
    pOutput->pkBytes = pInput->pkBytes;
2,089,664✔
3063
    (void)memcpy(pOutput->buf + pOutput->bytes, pInput->pkData, pOutput->pkBytes);
2,089,664✔
3064
    pOutput->pkData = pOutput->buf + pOutput->bytes;
2,089,664✔
3065
  }
3066
  return true;
1,506,872,086✔
3067
}
3068

3069
static int32_t firstLastTransferInfo(SqlFunctionCtx* pCtx, SFirstLastRes* pInput, SFirstLastRes* pOutput, bool isFirst,
1,510,892,277✔
3070
                                     int32_t rowIndex) {
3071
  if (firstLastTransferInfoImpl(pInput, pOutput, isFirst)) {
1,510,892,277✔
3072
    int32_t code = firstlastSaveTupleData(pCtx->pSrcBlock, rowIndex, pCtx, pOutput, false);
1,506,872,626✔
3073
    if (TSDB_CODE_SUCCESS != code) {
1,506,874,516✔
3074
      return code;
×
3075
    }
3076
    pOutput->hasResult = true;
1,506,874,516✔
3077
  }
3078
  return TSDB_CODE_SUCCESS;
1,510,895,247✔
3079
}
3080

3081
static int32_t firstLastFunctionMergeImpl(SqlFunctionCtx* pCtx, bool isFirstQuery) {
703,332,186✔
3082
  SInputColumnInfoData* pInput = &pCtx->input;
703,332,186✔
3083
  SColumnInfoData*      pCol = pInput->pData[0];
703,332,186✔
3084

3085
  if (IS_NULL_TYPE(pCol->info.type)) {
703,332,186✔
3086
    SET_VAL(GET_RES_INFO(pCtx), 0, 1);
×
3087
    return TSDB_CODE_SUCCESS;
×
3088
  }
3089

3090
  if (pCol->info.type != TSDB_DATA_TYPE_BINARY) {
703,332,456✔
3091
    return TSDB_CODE_FUNC_FUNTION_PARA_TYPE;
×
3092
  }
3093

3094
  SFirstLastRes* pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
703,332,456✔
3095

3096
  int32_t start = pInput->startRowIndex;
703,332,456✔
3097
  int32_t numOfElems = 0;
703,332,456✔
3098

3099
  for (int32_t i = start; i < start + pInput->numOfRows; ++i) {
2,147,483,647✔
3100
    if (colDataIsNull_s(pCol, i)) {
2,147,483,647✔
3101
      continue;
258,733,314✔
3102
    }
3103
    char*          data = colDataGetData(pCol, i);
1,510,892,817✔
3104
    SFirstLastRes* pInputInfo = (SFirstLastRes*)varDataVal(data);
1,510,893,627✔
3105
    if (pCtx->hasPrimaryKey) {
1,510,893,887✔
3106
      pInputInfo->pkData = pInputInfo->buf + pInputInfo->bytes;
2,206,711✔
3107
    } else {
3108
      pInputInfo->pkData = NULL;
1,508,687,176✔
3109
    }
3110

3111
    int32_t code = firstLastTransferInfo(pCtx, pInputInfo, pInfo, isFirstQuery, i);
1,510,892,277✔
3112
    if (code != TSDB_CODE_SUCCESS) {
1,510,895,517✔
3113
      return code;
×
3114
    }
3115
    if (!numOfElems) {
1,510,895,517✔
3116
      numOfElems = pInputInfo->hasResult ? 1 : 0;
699,013,626✔
3117
    }
3118
  }
3119

3120
  if (numOfElems == 0) {
703,330,026✔
3121
    int32_t code = firstlastSaveTupleData(pCtx->pSrcBlock, pInput->startRowIndex, pCtx, pInfo, true);
4,316,940✔
3122
    if (code != TSDB_CODE_SUCCESS) {
4,316,940✔
3123
      return code;
×
3124
    }
3125
    pInfo->nullTupleSaved = true;
4,316,940✔
3126
  }
3127

3128
  SET_VAL(GET_RES_INFO(pCtx), numOfElems, 1);
703,330,026✔
3129
  return TSDB_CODE_SUCCESS;
703,330,566✔
3130
}
3131

3132
int32_t firstFunctionMerge(SqlFunctionCtx* pCtx) { return firstLastFunctionMergeImpl(pCtx, true); }
409,852,772✔
3133

3134
int32_t lastFunctionMerge(SqlFunctionCtx* pCtx) { return firstLastFunctionMergeImpl(pCtx, false); }
293,479,414✔
3135

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

3144
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
2,147,483,647✔
3145
  pResInfo->isNullRes = (pResInfo->numOfRes == 0) ? 1 : 0;
2,147,483,647✔
3146

3147
  SFirstLastRes* pRes = GET_ROWCELL_INTERBUF(pResInfo);
2,147,483,647✔
3148

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

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

3164
  return code;
2,147,483,647✔
3165
}
3166

3167
int32_t firstLastPartialFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
1,879,614,593✔
3168
  int32_t code = TSDB_CODE_SUCCESS;
1,879,614,593✔
3169

3170
  SResultRowEntryInfo* pEntryInfo = GET_RES_INFO(pCtx);
1,879,614,593✔
3171
  SFirstLastRes*       pRes = GET_ROWCELL_INTERBUF(pEntryInfo);
1,880,206,318✔
3172

3173
  int32_t resultBytes = getFirstLastInfoSize(pRes->bytes, pRes->pkBytes);
1,880,157,532✔
3174

3175
  // todo check for failure
3176
  char* res = taosMemoryCalloc(resultBytes + VARSTR_HEADER_SIZE, sizeof(char));
1,879,827,369✔
3177
  if (NULL == res) {
1,872,149,526✔
3178
    return terrno;
×
3179
  }
3180
  (void)memcpy(varDataVal(res), pRes, resultBytes);
1,872,149,526✔
3181

3182
  varDataSetLen(res, resultBytes);
1,872,283,778✔
3183

3184
  int32_t          slotId = pCtx->pExpr->base.resSchema.slotId;
1,879,948,825✔
3185
  SColumnInfoData* pCol = taosArrayGet(pBlock->pDataBlock, slotId);
1,880,176,167✔
3186
  if (NULL == pCol) {
1,879,180,894✔
3187
    taosMemoryFree(res);
×
3188
    return TSDB_CODE_OUT_OF_RANGE;
×
3189
  }
3190

3191
  if (pEntryInfo->numOfRes == 0) {
1,879,180,894✔
3192
    colDataSetNULL(pCol, pBlock->info.rows);
269,629,524✔
3193
    code = setNullSelectivityValue(pCtx, pBlock, pBlock->info.rows);
269,620,488✔
3194
  } else {
3195
    code = colDataSetVal(pCol, pBlock->info.rows, res, false);
1,609,869,108✔
3196
    if (TSDB_CODE_SUCCESS != code) {
1,610,422,419✔
3197
      taosMemoryFree(res);
×
3198
      return code;
×
3199
    }
3200
    code = setSelectivityValue(pCtx, pBlock, &pRes->pos, pBlock->info.rows);
1,610,422,419✔
3201
  }
3202
  taosMemoryFree(res);
1,879,257,296✔
3203
  return code;
1,879,469,916✔
3204
}
3205

3206
int32_t lastCombine(SqlFunctionCtx* pDestCtx, SqlFunctionCtx* pSourceCtx) {
×
3207
  SResultRowEntryInfo* pDResInfo = GET_RES_INFO(pDestCtx);
×
3208
  SFirstLastRes*       pDBuf = GET_ROWCELL_INTERBUF(pDResInfo);
×
3209
  int32_t              bytes = pDBuf->bytes;
×
3210

3211
  SResultRowEntryInfo* pSResInfo = GET_RES_INFO(pSourceCtx);
×
3212
  SFirstLastRes*       pSBuf = GET_ROWCELL_INTERBUF(pSResInfo);
×
3213

3214
  pDBuf->hasResult = firstLastTransferInfoImpl(pSBuf, pDBuf, false);
×
3215
  pDResInfo->numOfRes = TMAX(pDResInfo->numOfRes, pSResInfo->numOfRes);
×
3216
  pDResInfo->isNullRes &= pSResInfo->isNullRes;
×
3217
  return TSDB_CODE_SUCCESS;
×
3218
}
3219

3220
static int32_t doSaveLastrow(SqlFunctionCtx* pCtx, char* pData, int32_t rowIndex, int64_t cts, SFirstLastRes* pInfo) {
24,910,616✔
3221
  SInputColumnInfoData* pInput = &pCtx->input;
24,910,616✔
3222
  SColumnInfoData*      pInputCol = pInput->pData[0];
24,917,806✔
3223
  SColumnInfoData*      pkCol = pInput->pPrimaryKey;
24,917,546✔
3224

3225
  if (colDataIsNull_s(pInputCol, rowIndex)) {
49,822,101✔
3226
    pInfo->isNull = true;
3,050,656✔
3227
  } else {
3228
    pInfo->isNull = false;
21,844,744✔
3229

3230
    if (IS_VAR_DATA_TYPE(pInputCol->info.type)) {
21,861,160✔
3231
      pInfo->bytes = calcStrBytesByType(pInputCol->info.type, pData);
3,813,511✔
3232
      // if (pInputCol->info.type == TSDB_DATA_TYPE_JSON) {
3233
      //   pInfo->bytes = getJsonValueLen(pData);
3234
      // } else {
3235
      //   pInfo->bytes = varDataTLen(pData);
3236
      // }
3237
    }
3238

3239
    (void)memcpy(pInfo->buf, pData, pInfo->bytes);
21,860,928✔
3240
  }
3241

3242
  if (pCtx->hasPrimaryKey && !colDataIsNull_s(pkCol, rowIndex)) {
34,474,858✔
3243
    char* pkData = colDataGetData(pkCol, rowIndex);
9,569,715✔
3244
    if (IS_VAR_DATA_TYPE(pInfo->pkType)) {
9,571,038✔
3245
      pInfo->pkBytes = calcStrBytesByType(pInfo->pkType, pkData);
3,186,276✔
3246
    }
3247
    (void)memcpy(pInfo->buf + pInfo->bytes, pkData, pInfo->pkBytes);
9,575,286✔
3248
    pInfo->pkData = pInfo->buf + pInfo->bytes;
9,557,855✔
3249
  }
3250
  pInfo->ts = cts;
24,911,991✔
3251
  int32_t code = firstlastSaveTupleData(pCtx->pSrcBlock, rowIndex, pCtx, pInfo, false);
24,922,963✔
3252
  if (code != TSDB_CODE_SUCCESS) {
24,902,995✔
3253
    return code;
×
3254
  }
3255

3256
  pInfo->hasResult = true;
24,902,995✔
3257

3258
  return TSDB_CODE_SUCCESS;
24,902,248✔
3259
}
3260

3261
int32_t lastRowFunction(SqlFunctionCtx* pCtx) {
2,147,483,647✔
3262
  int32_t numOfElems = 0;
2,147,483,647✔
3263

3264
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
2,147,483,647✔
3265
  SFirstLastRes*       pInfo = GET_ROWCELL_INTERBUF(pResInfo);
2,147,483,647✔
3266

3267
  SInputColumnInfoData* pInput = &pCtx->input;
2,147,483,647✔
3268
  SColumnInfoData*      pInputCol = pInput->pData[0];
2,147,483,647✔
3269

3270
  int32_t type = pInputCol->info.type;
2,147,483,647✔
3271
  int32_t bytes = pInputCol->info.bytes;
2,147,483,647✔
3272
  pInfo->bytes = bytes;
2,147,483,647✔
3273

3274
  if (IS_NULL_TYPE(type)) {
2,147,483,647✔
3275
    return TSDB_CODE_SUCCESS;
21,243✔
3276
  }
3277
  SColumnInfoData* pkCol = pInput->pPrimaryKey;
2,147,483,647✔
3278
  pInfo->pkType = -1;
2,147,483,647✔
3279
  __compar_fn_t pkCompareFn = NULL;
2,147,483,647✔
3280
  if (pCtx->hasPrimaryKey) {
2,147,483,647✔
3281
    pInfo->pkType = pkCol->info.type;
52,476,520✔
3282
    pInfo->pkBytes = pkCol->info.bytes;
52,480,742✔
3283
    pkCompareFn = getKeyComparFunc(pInfo->pkType, TSDB_ORDER_DESC);
52,477,212✔
3284
  }
3285
  TSKEY startKey = getRowPTs(pInput->pPTS, 0);
2,147,483,647✔
3286
  TSKEY endKey = getRowPTs(pInput->pPTS, pInput->totalRows - 1);
2,147,483,647✔
3287

3288
  if (pCtx->order == TSDB_ORDER_ASC && !pCtx->hasPrimaryKey) {
2,147,483,647✔
3289
    for (int32_t i = pInput->numOfRows + pInput->startRowIndex - 1; i >= pInput->startRowIndex; --i) {
23,421,818✔
3290
      bool  isNull = colDataIsNull(pInputCol, pInput->numOfRows, i, NULL);
11,710,909✔
3291
      char* data = isNull ? NULL : colDataGetData(pInputCol, i);
11,710,909✔
3292
      TSKEY cts = getRowPTs(pInput->pPTS, i);
11,710,909✔
3293
      numOfElems++;
11,711,411✔
3294

3295
      if (pResInfo->numOfRes == 0 || pInfo->ts < cts) {
11,711,411✔
3296
        int32_t code = doSaveLastrow(pCtx, data, i, cts, pInfo);
3,279,775✔
3297
        if (code != TSDB_CODE_SUCCESS) return code;
3,278,771✔
3298
      }
3299

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

3311
      if (pResInfo->numOfRes == 0 || pInfo->ts < cts) {
2,147,483,647✔
3312
        int32_t code = doSaveLastrow(pCtx, data, i, cts, pInfo);
9,208,934✔
3313
        if (code != TSDB_CODE_SUCCESS) return code;
9,734,989✔
3314
      }
3315
      break;
2,147,483,647✔
3316
    }
3317
  } else {
3318
    int64_t* pts = (int64_t*)pInput->pPTS->pData;
52,411,941✔
3319
    int      from = -1;
53,106,043✔
3320
    int32_t  i = -1;
53,111,269✔
3321
    while (funcInputGetNextRowIndex(pInput, from, false, &i, &from)) {
246,230,100✔
3322
      bool  isNull = colDataIsNull(pInputCol, pInput->numOfRows, i, NULL);
193,097,379✔
3323
      char* data = isNull ? NULL : colDataGetData(pInputCol, i);
193,133,077✔
3324
      TSKEY cts = pts[i];
193,123,284✔
3325

3326
      numOfElems++;
193,117,231✔
3327
      char* pkData = NULL;
193,117,231✔
3328
      if (pCtx->hasPrimaryKey) {
193,117,231✔
3329
        pkData = colDataGetData(pkCol, i);
188,237,543✔
3330
      }
3331
      if (pResInfo->numOfRes == 0 || pInfo->ts < cts ||
193,103,461✔
3332
          (pInfo->ts == pts[i] && pkCompareFn && pkCompareFn(pkData, pInfo->pkData) < 0)) {
181,810,427✔
3333
        int32_t code = doSaveLastrow(pCtx, data, i, cts, pInfo);
11,288,844✔
3334
        if (code != TSDB_CODE_SUCCESS) {
11,324,527✔
3335
          return code;
×
3336
        }
3337
        pResInfo->numOfRes = 1;
11,324,527✔
3338
      }
3339
    }
3340
  }
3341

3342
  SET_VAL(pResInfo, numOfElems, 1);
2,147,483,647✔
3343
  return TSDB_CODE_SUCCESS;
2,147,483,647✔
3344
}
3345

3346
bool getDiffFuncEnv(SFunctionNode* UNUSED_PARAM(pFunc), SFuncExecEnv* pEnv) {
603,042✔
3347
  pEnv->calcMemSize = sizeof(SDiffInfo);
603,042✔
3348
  return true;
603,042✔
3349
}
3350

3351
int32_t diffFunctionSetup(SqlFunctionCtx* pCtx, SResultRowEntryInfo* pResInfo) {
71,614,155✔
3352
  if (pResInfo->initialized) {
71,614,155✔
3353
    return TSDB_CODE_SUCCESS;
54,922,511✔
3354
  }
3355
  if (TSDB_CODE_SUCCESS != functionSetup(pCtx, pResInfo)) {
16,691,644✔
3356
    return TSDB_CODE_FUNC_SETUP_ERROR;
×
3357
  }
3358
  SDiffInfo* pDiffInfo = GET_ROWCELL_INTERBUF(pResInfo);
16,691,644✔
3359
  pDiffInfo->hasPrev = false;
16,691,644✔
3360
  pDiffInfo->isFirstRow = true;
16,691,644✔
3361
  pDiffInfo->prev.i64 = 0;
16,691,644✔
3362
  pDiffInfo->prevTs = -1;
16,691,644✔
3363
  if (pCtx->numOfParams > 1) {
16,691,644✔
3364
    pDiffInfo->ignoreOption = pCtx->param[1].param.i;  // TODO set correct param
16,691,644✔
3365
  } else {
3366
    pDiffInfo->ignoreOption = 0;
×
3367
  }
3368
  return TSDB_CODE_SUCCESS;
16,691,644✔
3369
}
3370

3371
static int32_t doSetPrevVal(SDiffInfo* pDiffInfo, int32_t type, const char* pv, int64_t ts) {
16,573,342✔
3372
  switch (type) {
16,573,342✔
3373
    case TSDB_DATA_TYPE_BOOL:
4,401✔
3374
      pDiffInfo->prev.i64 = *(bool*)pv ? 1 : 0;
4,401✔
3375
      break;
4,401✔
3376
    case TSDB_DATA_TYPE_UTINYINT:
37,402✔
3377
    case TSDB_DATA_TYPE_TINYINT:
3378
      pDiffInfo->prev.i64 = *(int8_t*)pv;
37,402✔
3379
      break;
37,402✔
3380
    case TSDB_DATA_TYPE_UINT:
16,263,212✔
3381
    case TSDB_DATA_TYPE_INT:
3382
      pDiffInfo->prev.i64 = *(int32_t*)pv;
16,263,212✔
3383
      break;
16,263,212✔
3384
    case TSDB_DATA_TYPE_USMALLINT:
39,630✔
3385
    case TSDB_DATA_TYPE_SMALLINT:
3386
      pDiffInfo->prev.i64 = *(int16_t*)pv;
39,630✔
3387
      break;
39,630✔
3388
    case TSDB_DATA_TYPE_TIMESTAMP:
135,323✔
3389
    case TSDB_DATA_TYPE_UBIGINT:
3390
    case TSDB_DATA_TYPE_BIGINT:
3391
      pDiffInfo->prev.i64 = *(int64_t*)pv;
135,323✔
3392
      break;
135,323✔
3393
    case TSDB_DATA_TYPE_FLOAT:
24,215✔
3394
      pDiffInfo->prev.d64 = *(float*)pv;
24,215✔
3395
      break;
24,215✔
3396
    case TSDB_DATA_TYPE_DOUBLE:
69,159✔
3397
      pDiffInfo->prev.d64 = *(double*)pv;
69,159✔
3398
      break;
69,159✔
3399
    default:
×
3400
      return TSDB_CODE_FUNC_FUNTION_PARA_TYPE;
×
3401
  }
3402
  pDiffInfo->prevTs = ts;
16,573,342✔
3403
  pDiffInfo->hasPrev = true;
16,573,342✔
3404
  return TSDB_CODE_SUCCESS;
16,573,342✔
3405
}
3406

3407
static bool diffIsNegtive(SDiffInfo* pDiffInfo, int32_t type, const char* pv) {
2,346,127✔
3408
  switch (type) {
2,346,127✔
3409
    case TSDB_DATA_TYPE_UINT: {
×
3410
      int64_t v = *(uint32_t*)pv;
×
3411
      return v < pDiffInfo->prev.i64;
×
3412
    }
3413
    case TSDB_DATA_TYPE_INT: {
121,500✔
3414
      int64_t v = *(int32_t*)pv;
121,500✔
3415
      return v < pDiffInfo->prev.i64;
121,500✔
3416
    }
3417
    case TSDB_DATA_TYPE_BOOL: {
×
3418
      int64_t v = *(bool*)pv;
×
3419
      return v < pDiffInfo->prev.i64;
×
3420
    }
3421
    case TSDB_DATA_TYPE_UTINYINT: {
×
3422
      int64_t v = *(uint8_t*)pv;
×
3423
      return v < pDiffInfo->prev.i64;
×
3424
    }
3425
    case TSDB_DATA_TYPE_TINYINT: {
560,893✔
3426
      int64_t v = *(int8_t*)pv;
560,893✔
3427
      return v < pDiffInfo->prev.i64;
560,893✔
3428
    }
3429
    case TSDB_DATA_TYPE_USMALLINT: {
×
3430
      int64_t v = *(uint16_t*)pv;
×
3431
      return v < pDiffInfo->prev.i64;
×
3432
    }
3433
    case TSDB_DATA_TYPE_SMALLINT: {
486,149✔
3434
      int64_t v = *(int16_t*)pv;
486,149✔
3435
      return v < pDiffInfo->prev.i64;
486,149✔
3436
    }
3437
    case TSDB_DATA_TYPE_UBIGINT: {
3,912✔
3438
      uint64_t v = *(uint64_t*)pv;
3,912✔
3439
      return v < (uint64_t)pDiffInfo->prev.i64;
3,912✔
3440
    }
3441
    case TSDB_DATA_TYPE_TIMESTAMP:
474,013✔
3442
    case TSDB_DATA_TYPE_BIGINT: {
3443
      int64_t v = *(int64_t*)pv;
474,013✔
3444
      return v < pDiffInfo->prev.i64;
474,013✔
3445
    }
3446
    case TSDB_DATA_TYPE_FLOAT: {
349,830✔
3447
      float v = *(float*)pv;
349,830✔
3448
      return v < pDiffInfo->prev.d64;
349,830✔
3449
    }
3450
    case TSDB_DATA_TYPE_DOUBLE: {
349,830✔
3451
      double v = *(double*)pv;
349,830✔
3452
      return v < pDiffInfo->prev.d64;
349,830✔
3453
    }
3454
    default:
×
3455
      return false;
×
3456
  }
3457

3458
  return false;
3459
}
3460

3461
static void tryToSetInt64(SDiffInfo* pDiffInfo, int32_t type, SColumnInfoData* pOutput, int64_t v, int32_t pos) {
2,147,483,647✔
3462
  bool isNegative = v < pDiffInfo->prev.i64;
2,147,483,647✔
3463
  if (type == TSDB_DATA_TYPE_UBIGINT) {
2,147,483,647✔
3464
    isNegative = (uint64_t)v < (uint64_t)pDiffInfo->prev.i64;
492,205✔
3465
  }
3466
  int64_t delta = v - pDiffInfo->prev.i64;
2,147,483,647✔
3467
  if (isNegative && ignoreNegative(pDiffInfo->ignoreOption)) {
2,147,483,647✔
3468
    colDataSetNull_f_s(pOutput, pos);
800,013✔
3469
    pOutput->hasNull = true;
800,013✔
3470
  } else {
3471
    colDataSetInt64(pOutput, pos, &delta);
2,147,483,647✔
3472
  }
3473
  pDiffInfo->prev.i64 = v;
2,147,483,647✔
3474
}
2,147,483,647✔
3475

3476
static void tryToSetDouble(SDiffInfo* pDiffInfo, SColumnInfoData* pOutput, double v, int32_t pos) {
32,261,492✔
3477
  double delta = v - pDiffInfo->prev.d64;
32,261,492✔
3478
  if (delta < 0 && ignoreNegative(pDiffInfo->ignoreOption)) {
32,261,492✔
3479
    colDataSetNull_f_s(pOutput, pos);
339,997✔
3480
  } else {
3481
    colDataSetDouble(pOutput, pos, &delta);
31,921,495✔
3482
  }
3483
  pDiffInfo->prev.d64 = v;
32,261,492✔
3484
}
32,261,492✔
3485

3486
static int32_t doHandleDiff(SDiffInfo* pDiffInfo, int32_t type, const char* pv, SColumnInfoData* pOutput, int32_t pos,
2,147,483,647✔
3487
                            int64_t ts) {
3488
  if (!pDiffInfo->hasPrev) {
2,147,483,647✔
3489
    colDataSetNull_f_s(pOutput, pos);
72,906✔
3490
    return doSetPrevVal(pDiffInfo, type, pv, ts);
72,906✔
3491
  }
3492
  pDiffInfo->prevTs = ts;
2,147,483,647✔
3493
  switch (type) {
2,147,483,647✔
3494
    case TSDB_DATA_TYPE_UINT: {
485,359✔
3495
      int64_t v = *(uint32_t*)pv;
485,359✔
3496
      tryToSetInt64(pDiffInfo, type, pOutput, v, pos);
485,359✔
3497
      break;
485,359✔
3498
    }
3499
    case TSDB_DATA_TYPE_INT: {
2,147,483,647✔
3500
      int64_t v = *(int32_t*)pv;
2,147,483,647✔
3501
      tryToSetInt64(pDiffInfo, type, pOutput, v, pos);
2,147,483,647✔
3502
      break;
2,147,483,647✔
3503
    }
3504
    case TSDB_DATA_TYPE_BOOL: {
4,980,954✔
3505
      int64_t v = *(bool*)pv;
4,980,954✔
3506
      tryToSetInt64(pDiffInfo, type, pOutput, v, pos);
4,980,954✔
3507
      break;
4,980,954✔
3508
    }
3509
    case TSDB_DATA_TYPE_UTINYINT: {
66,977✔
3510
      int64_t v = *(uint8_t*)pv;
66,977✔
3511
      tryToSetInt64(pDiffInfo, type, pOutput, v, pos);
66,977✔
3512
      break;
66,977✔
3513
    }
3514
    case TSDB_DATA_TYPE_TINYINT: {
11,004,652✔
3515
      int64_t v = *(int8_t*)pv;
11,004,652✔
3516
      tryToSetInt64(pDiffInfo, type, pOutput, v, pos);
11,004,652✔
3517
      break;
11,004,652✔
3518
    }
3519
    case TSDB_DATA_TYPE_USMALLINT: {
66,977✔
3520
      int64_t v = *(uint16_t*)pv;
66,977✔
3521
      tryToSetInt64(pDiffInfo, type, pOutput, v, pos);
66,977✔
3522
      break;
66,977✔
3523
    }
3524
    case TSDB_DATA_TYPE_SMALLINT: {
11,068,508✔
3525
      int64_t v = *(int16_t*)pv;
11,068,508✔
3526
      tryToSetInt64(pDiffInfo, type, pOutput, v, pos);
11,068,508✔
3527
      break;
11,068,508✔
3528
    }
3529
    case TSDB_DATA_TYPE_TIMESTAMP:
2,147,483,647✔
3530
    case TSDB_DATA_TYPE_UBIGINT:
3531
    case TSDB_DATA_TYPE_BIGINT: {
3532
      int64_t v = *(int64_t*)pv;
2,147,483,647✔
3533
      tryToSetInt64(pDiffInfo, type, pOutput, v, pos);
2,147,483,647✔
3534
      break;
2,147,483,647✔
3535
    }
3536
    case TSDB_DATA_TYPE_FLOAT: {
15,815,895✔
3537
      double v = *(float*)pv;
15,815,895✔
3538
      tryToSetDouble(pDiffInfo, pOutput, v, pos);
15,815,895✔
3539
      break;
15,815,895✔
3540
    }
3541
    case TSDB_DATA_TYPE_DOUBLE: {
16,445,597✔
3542
      double v = *(double*)pv;
16,445,597✔
3543
      tryToSetDouble(pDiffInfo, pOutput, v, pos);
16,445,597✔
3544
      break;
16,445,597✔
3545
    }
3546
    default:
×
3547
      return TSDB_CODE_FUNC_FUNTION_PARA_TYPE;
×
3548
  }
3549
  pDiffInfo->hasPrev = true;
2,147,483,647✔
3550
  return TSDB_CODE_SUCCESS;
2,147,483,647✔
3551
}
3552

3553
// TODO: the primary key compare can be skipped for ordered pk if knonwn before
3554
// TODO: for desc ordered, pk shall select the smallest one for one ts. if across block boundaries.
3555
bool funcInputGetNextRowIndex(SInputColumnInfoData* pInput, int32_t from, bool firstOccur, int32_t* pRowIndex,
2,147,483,647✔
3556
                              int32_t* nextFrom) {
3557
  if (pInput->pPrimaryKey == NULL) {
2,147,483,647✔
3558
    if (pInput->numOfRows == 0) {
2,147,483,647✔
3559
      return false;
×
3560
    }
3561
    if (from == -1) {
2,147,483,647✔
3562
      from = pInput->startRowIndex;
2,147,483,647✔
3563
    } else if (from >= pInput->numOfRows + pInput->startRowIndex) {
2,147,483,647✔
3564
      return false;
2,147,483,647✔
3565
    }
3566
    *pRowIndex = from;
2,147,483,647✔
3567
    *nextFrom = from + 1;
2,147,483,647✔
3568
    return true;
2,147,483,647✔
3569
  } else {
3570
    if (from == -1) {
726,120,811✔
3571
      from = pInput->startRowIndex;
158,585,600✔
3572
    } else if (from >= pInput->numOfRows + pInput->startRowIndex) {
567,535,211✔
3573
      return false;
158,679,273✔
3574
    }
3575
    TSKEY*           tsList = (int64_t*)pInput->pPTS->pData;
567,523,211✔
3576
    SColumnInfoData* pkCol = pInput->pPrimaryKey;
567,602,024✔
3577
    int8_t           pkType = pkCol->info.type;
567,521,432✔
3578
    int32_t          order = (firstOccur) ? TSDB_ORDER_ASC : TSDB_ORDER_DESC;
567,655,962✔
3579
    __compar_fn_t    compareFunc = getKeyComparFunc(pkType, order);
567,655,962✔
3580
    int32_t          select = from;
567,494,424✔
3581
    char*            val = colDataGetData(pkCol, select);
567,494,424✔
3582
    while (from < pInput->numOfRows + pInput->startRowIndex - 1 && tsList[from + 1] == tsList[from]) {
1,421,828,737✔
3583
      char* val1 = colDataGetData(pkCol, from + 1);
854,261,111✔
3584
      if (compareFunc(val1, val) < 0) {
854,401,346✔
3585
        select = from + 1;
273,740,244✔
3586
        val = val1;
273,740,244✔
3587
      }
3588
      from = from + 1;
854,238,113✔
3589
    }
3590
    *pRowIndex = select;
567,097,184✔
3591
    *nextFrom = from + 1;
567,536,270✔
3592
    return true;
567,547,975✔
3593
  }
3594
}
3595

3596
bool getForecastConfEnv(SFunctionNode* UNUSED_PARAM(pFunc), SFuncExecEnv* pEnv) {
×
3597
  pEnv->calcMemSize = sizeof(double);
×
3598
  return true;
×
3599
}
3600

3601
int32_t diffResultIsNull(SqlFunctionCtx* pCtx, SFuncInputRow* pRow) {
2,147,483,647✔
3602
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
2,147,483,647✔
3603
  SDiffInfo*           pDiffInfo = GET_ROWCELL_INTERBUF(pResInfo);
2,147,483,647✔
3604

3605
  if (pRow->isDataNull || !pDiffInfo->hasPrev) {
2,147,483,647✔
3606
    return true;
25,253,752✔
3607
  } else if (ignoreNegative(pDiffInfo->ignoreOption)) {
2,147,483,647✔
3608
    return diffIsNegtive(pDiffInfo, pCtx->input.pData[0]->info.type, pRow->pData);
2,346,127✔
3609
  }
3610
  return false;
2,147,483,647✔
3611
}
3612

3613
bool isFirstRow(SqlFunctionCtx* pCtx, SFuncInputRow* pRow) {
2,147,483,647✔
3614
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
2,147,483,647✔
3615
  SDiffInfo*           pDiffInfo = GET_ROWCELL_INTERBUF(pResInfo);
2,147,483,647✔
3616
  return pDiffInfo->isFirstRow;
2,147,483,647✔
3617
}
3618

3619
int32_t trySetPreVal(SqlFunctionCtx* pCtx, SFuncInputRow* pRow) {
16,701,648✔
3620
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
16,701,648✔
3621
  SDiffInfo*           pDiffInfo = GET_ROWCELL_INTERBUF(pResInfo);
16,701,648✔
3622
  pDiffInfo->isFirstRow = false;
16,701,648✔
3623
  if (pRow->isDataNull) {
16,701,648✔
3624
    return TSDB_CODE_SUCCESS;
201,212✔
3625
  }
3626

3627
  SInputColumnInfoData* pInput = &pCtx->input;
16,500,436✔
3628
  SColumnInfoData*      pInputCol = pInput->pData[0];
16,500,436✔
3629
  int8_t                inputType = pInputCol->info.type;
16,500,436✔
3630

3631
  char* pv = pRow->pData;
16,500,436✔
3632
  return doSetPrevVal(pDiffInfo, inputType, pv, pRow->ts);
16,500,436✔
3633
}
3634

3635
int32_t setDoDiffResult(SqlFunctionCtx* pCtx, SFuncInputRow* pRow, int32_t pos) {
2,147,483,647✔
3636
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
2,147,483,647✔
3637
  SDiffInfo*           pDiffInfo = GET_ROWCELL_INTERBUF(pResInfo);
2,147,483,647✔
3638

3639
  SInputColumnInfoData* pInput = &pCtx->input;
2,147,483,647✔
3640
  SColumnInfoData*      pInputCol = pInput->pData[0];
2,147,483,647✔
3641
  int8_t                inputType = pInputCol->info.type;
2,147,483,647✔
3642
  SColumnInfoData*      pOutput = (SColumnInfoData*)pCtx->pOutput;
2,147,483,647✔
3643
  int32_t               code = TSDB_CODE_SUCCESS;
2,147,483,647✔
3644
  if (pRow->isDataNull) {
2,147,483,647✔
3645
    colDataSetNull_f_s(pOutput, pos);
8,487,511✔
3646
    pOutput->hasNull = true;
8,487,511✔
3647

3648
    // handle selectivity
3649
    if (pCtx->subsidiaries.num > 0) {
8,487,511✔
3650
      code = appendSelectivityCols(pCtx, pRow->block, pRow->rowIndex, pos);
23,472✔
3651
      if (code != TSDB_CODE_SUCCESS) {
23,472✔
3652
        return code;
×
3653
      }
3654
    }
3655
    return TSDB_CODE_SUCCESS;
8,487,511✔
3656
  }
3657

3658
  char* pv = pRow->pData;
2,147,483,647✔
3659

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

3675
  return TSDB_CODE_SUCCESS;
2,147,483,647✔
3676
}
3677

3678
int32_t diffFunction(SqlFunctionCtx* pCtx) { return TSDB_CODE_SUCCESS; }
60,652,417✔
3679

3680
int32_t diffFunctionByRow(SArray* pCtxArray) {
60,617,353✔
3681
  int32_t code = TSDB_CODE_SUCCESS;
60,617,353✔
3682
  int     diffColNum = pCtxArray->size;
60,617,353✔
3683
  if (diffColNum == 0) {
60,617,353✔
3684
    return TSDB_CODE_SUCCESS;
×
3685
  }
3686
  int32_t numOfElems = 0;
60,617,353✔
3687

3688
  SArray* pRows = taosArrayInit_s(sizeof(SFuncInputRow), diffColNum);
60,617,353✔
3689
  if (NULL == pRows) {
60,617,353✔
3690
    return terrno;
×
3691
  }
3692

3693
  bool keepNull = false;
60,617,353✔
3694
  for (int i = 0; i < diffColNum; ++i) {
121,269,770✔
3695
    SqlFunctionCtx* pCtx = *(SqlFunctionCtx**)taosArrayGet(pCtxArray, i);
60,652,417✔
3696
    if (NULL == pCtx) {
60,652,417✔
3697
      code = terrno;
×
3698
      goto _exit;
×
3699
    }
3700
    funcInputUpdate(pCtx);
60,652,417✔
3701
    SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
60,652,417✔
3702
    SDiffInfo*           pDiffInfo = GET_ROWCELL_INTERBUF(pResInfo);
60,652,417✔
3703
    if (!ignoreNull(pDiffInfo->ignoreOption)) {
60,652,417✔
3704
      keepNull = true;
60,632,368✔
3705
    }
3706
  }
3707

3708
  SqlFunctionCtx* pCtx0 = *(SqlFunctionCtx**)taosArrayGet(pCtxArray, 0);
60,617,353✔
3709
  SFuncInputRow*  pRow0 = (SFuncInputRow*)taosArrayGet(pRows, 0);
60,617,353✔
3710
  if (NULL == pCtx0 || NULL == pRow0) {
60,617,353✔
3711
    code = terrno;
×
3712
    goto _exit;
×
3713
  }
3714
  int32_t startOffset = pCtx0->offset;
60,617,353✔
3715
  bool    result = false;
60,617,353✔
3716
  while (1) {
2,147,483,647✔
3717
    code = funcInputGetNextRow(pCtx0, pRow0, &result);
2,147,483,647✔
3718
    if (TSDB_CODE_SUCCESS != code) {
2,147,483,647✔
3719
      goto _exit;
×
3720
    }
3721
    if (!result) {
2,147,483,647✔
3722
      break;
60,608,502✔
3723
    }
3724
    bool hasNotNullValue = !diffResultIsNull(pCtx0, pRow0);
2,147,483,647✔
3725
    for (int i = 1; i < diffColNum; ++i) {
2,147,483,647✔
3726
      SqlFunctionCtx* pCtx = *(SqlFunctionCtx**)taosArrayGet(pCtxArray, i);
5,639,838✔
3727
      SFuncInputRow*  pRow = (SFuncInputRow*)taosArrayGet(pRows, i);
5,639,838✔
3728
      if (NULL == pCtx || NULL == pRow) {
5,639,838✔
3729
        code = terrno;
×
3730
        goto _exit;
×
3731
      }
3732
      code = funcInputGetNextRow(pCtx, pRow, &result);
5,639,838✔
3733
      if (TSDB_CODE_SUCCESS != code) {
5,639,838✔
3734
        goto _exit;
×
3735
      }
3736
      if (!result) {
5,639,838✔
3737
        // rows are not equal
3738
        code = TSDB_CODE_QRY_EXECUTOR_INTERNAL_ERROR;
×
3739
        goto _exit;
×
3740
      }
3741
      if (!diffResultIsNull(pCtx, pRow)) {
5,639,838✔
3742
        hasNotNullValue = true;
5,558,808✔
3743
      }
3744
    }
3745
    int32_t pos = startOffset + numOfElems;
2,147,483,647✔
3746

3747
    bool newRow = false;
2,147,483,647✔
3748
    for (int i = 0; i < diffColNum; ++i) {
2,147,483,647✔
3749
      SqlFunctionCtx* pCtx = *(SqlFunctionCtx**)taosArrayGet(pCtxArray, i);
2,147,483,647✔
3750
      SFuncInputRow*  pRow = (SFuncInputRow*)taosArrayGet(pRows, i);
2,147,483,647✔
3751
      if (NULL == pCtx || NULL == pRow) {
2,147,483,647✔
3752
        code = terrno;
×
3753
        goto _exit;
×
3754
      }
3755
      if ((keepNull || hasNotNullValue) && !isFirstRow(pCtx, pRow)) {
2,147,483,647✔
3756
        code = setDoDiffResult(pCtx, pRow, pos);
2,147,483,647✔
3757
        if (code != TSDB_CODE_SUCCESS) {
2,147,483,647✔
3758
          goto _exit;
8,851✔
3759
        }
3760
        newRow = true;
2,147,483,647✔
3761
      } else {
3762
        code = trySetPreVal(pCtx, pRow);
16,701,648✔
3763
        if (code != TSDB_CODE_SUCCESS) {
16,701,648✔
3764
          goto _exit;
×
3765
        }
3766
      }
3767
    }
3768
    if (newRow) ++numOfElems;
2,147,483,647✔
3769
  }
3770

3771
  for (int i = 0; i < diffColNum; ++i) {
121,251,579✔
3772
    SqlFunctionCtx* pCtx = *(SqlFunctionCtx**)taosArrayGet(pCtxArray, i);
60,643,077✔
3773
    if (NULL == pCtx) {
60,643,077✔
3774
      code = terrno;
×
3775
      goto _exit;
×
3776
    }
3777
    SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
60,643,077✔
3778
    pResInfo->numOfRes = numOfElems;
60,643,077✔
3779
  }
3780

3781
_exit:
60,617,353✔
3782
  if (pRows) {
60,617,353✔
3783
    taosArrayDestroy(pRows);
60,617,353✔
3784
    pRows = NULL;
60,617,353✔
3785
  }
3786
  return code;
60,617,353✔
3787
}
3788

3789
typedef struct {
3790
  SArray* pLagTail;
3791
  SArray* pLeadPending;
3792
} SLagLeadState;
3793

3794
bool getLagFuncEnv(SFunctionNode* UNUSED_PARAM(pFunc), SFuncExecEnv* pEnv) {
23,635✔
3795
  pEnv->calcMemSize = sizeof(SLagLeadState);
23,635✔
3796
  return true;
23,635✔
3797
}
3798

3799
int32_t lagFunctionSetup(SqlFunctionCtx* pCtx, SResultRowEntryInfo* pResInfo) {
59,944✔
3800
  if (pResInfo->initialized) {
59,944✔
3801
    return TSDB_CODE_SUCCESS;
30,962✔
3802
  }
3803
  if (TSDB_CODE_SUCCESS != functionSetup(pCtx, pResInfo)) {
28,982✔
3804
    return TSDB_CODE_FUNC_SETUP_ERROR;
×
3805
  }
3806

3807
  SLagLeadState* pState = GET_ROWCELL_INTERBUF(pResInfo);
28,982✔
3808
  if (pState != NULL) {
28,982✔
3809
    pState->pLagTail = NULL;
28,982✔
3810
    pState->pLeadPending = NULL;
28,982✔
3811
  }
3812

3813
  return TSDB_CODE_SUCCESS;
28,982✔
3814
}
3815

3816
int32_t lagFunction(SqlFunctionCtx* UNUSED_PARAM(pCtx)) { return TSDB_CODE_SUCCESS; }
31,952✔
3817

3818
typedef struct {
3819
  bool        isDataNull;
3820
  char*       pData;
3821
  int32_t     dataLen;
3822
  SSDataBlock* block;
3823
  int32_t     rowIndex;
3824
} SLagLeadRowValue;
3825

3826
typedef struct {
3827
  int32_t outputPos;
3828
  int64_t needIdx;
3829
} SLeadPendingItem;
3830

3831
static void cleanupLagLeadRowValueArray(SArray* pValues) {
103,866✔
3832
  if (pValues == NULL) {
103,866✔
3833
    return;
×
3834
  }
3835

3836
  int32_t size = taosArrayGetSize(pValues);
103,866✔
3837
  for (int32_t i = 0; i < size; ++i) {
52,093,069✔
3838
    SLagLeadRowValue* pValue = (SLagLeadRowValue*)taosArrayGet(pValues, i);
51,989,203✔
3839
    if (pValue != NULL && pValue->pData != NULL) {
51,989,203✔
3840
      taosMemoryFree(pValue->pData);
51,984,253✔
3841
      pValue->pData = NULL;
51,984,253✔
3842
    }
3843
  }
3844

3845
  taosArrayDestroy(pValues);
103,866✔
3846
}
3847

3848
static void cleanupLagLeadValueArrays(SArray* pValueArrays) {
68,699✔
3849
  if (pValueArrays == NULL) {
68,699✔
3850
    return;
×
3851
  }
3852

3853
  int32_t size = taosArrayGetSize(pValueArrays);
68,699✔
3854
  for (int32_t i = 0; i < size; ++i) {
140,613✔
3855
    SArray** ppValues = (SArray**)taosArrayGet(pValueArrays, i);
71,914✔
3856
    if (ppValues != NULL && *ppValues != NULL) {
71,914✔
3857
      cleanupLagLeadRowValueArray(*ppValues);
71,914✔
3858
    }
3859
  }
3860

3861
  taosArrayDestroy(pValueArrays);
68,699✔
3862
}
3863

3864
static int32_t copyLagLeadRowValue(SqlFunctionCtx* pCtx, SFuncInputRow* pRow, SLagLeadRowValue* pValue) {
39,788,716✔
3865
  pValue->isDataNull = pRow->isDataNull;
39,788,716✔
3866
  pValue->pData = NULL;
39,788,716✔
3867
  pValue->dataLen = 0;
39,788,716✔
3868
  pValue->block = pRow->block;
39,788,716✔
3869
  pValue->rowIndex = pRow->rowIndex;
39,788,716✔
3870

3871
  if (pRow->isDataNull) {
39,788,716✔
3872
    return TSDB_CODE_SUCCESS;
3,960✔
3873
  }
3874

3875
  SColumnInfoData* pInputCol = pCtx->input.pData[0];
39,784,756✔
3876
  int32_t          dataLen = pInputCol->info.bytes;
39,784,756✔
3877
  if (IS_VAR_DATA_TYPE(pInputCol->info.type)) {
39,784,756✔
3878
    dataLen = IS_STR_DATA_BLOB(pInputCol->info.type) ? blobDataTLen(pRow->pData) : varDataTLen(pRow->pData);
4,961,880✔
3879
  }
3880
  pValue->dataLen = dataLen;
39,784,756✔
3881
  pValue->pData = taosMemoryMalloc(dataLen);
39,784,756✔
3882
  if (pValue->pData == NULL) {
39,784,756✔
3883
    return terrno;
×
3884
  }
3885

3886
  (void)memcpy(pValue->pData, pRow->pData, dataLen);
39,784,756✔
3887
  return TSDB_CODE_SUCCESS;
39,784,756✔
3888
}
3889

3890
static int32_t setLagLeadDefaultValue(SqlFunctionCtx* pCtx, int32_t pos) {
14,030,319✔
3891
  if (pCtx->numOfParams < 3) {
14,030,319✔
3892
    colDataSetNULL((SColumnInfoData*)pCtx->pOutput, pos);
×
3893
    return TSDB_CODE_SUCCESS;
×
3894
  }
3895

3896
  SVariant* pDefault = &pCtx->param[2].param;
14,030,319✔
3897

3898
  if (IS_NULL_TYPE(pDefault->nType)) {
14,030,319✔
3899
    colDataSetNULL((SColumnInfoData*)pCtx->pOutput, pos);
25,425✔
3900
    return TSDB_CODE_SUCCESS;
25,425✔
3901
  }
3902

3903
  SColumnInfoData* pOutput = (SColumnInfoData*)pCtx->pOutput;
14,004,894✔
3904
  uint8_t          type = pOutput->info.type;
14,004,894✔
3905
  STypeMod         inputTypeMod = pCtx->param[2].pCol == NULL ? 0 : typeGetTypeModFromCol(pCtx->param[2].pCol);
14,004,894✔
3906
  int32_t          retCode = TSDB_CODE_SUCCESS;
14,004,894✔
3907

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

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

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

4082
      if (retCode == TSDB_CODE_SUCCESS) {
×
4083
        retCode = colDataSetVal(pOutput, pos, (const char*)&v, false);
×
4084
      }
4085
      break;
×
4086
    }
4087
    case TSDB_DATA_TYPE_GEOMETRY:
1,980✔
4088
      if (pDefault->pz == NULL) {
1,980✔
4089
        colDataSetNULL(pOutput, pos);
×
4090
        retCode = TSDB_CODE_SUCCESS;
×
4091
        break;
×
4092
      }
4093

4094
      if (pDefault->nType == TSDB_DATA_TYPE_GEOMETRY) {
1,980✔
4095
        retCode = colDataSetVal(pOutput, pos, pDefault->pz, false);
×
4096
        break;
×
4097
      }
4098

4099
      if (IS_STR_DATA_TYPE(pDefault->nType)) {
1,980✔
4100
#ifdef USE_GEOS
4101
        size_t         len = 0;
1,980✔
4102
        unsigned char* geom = NULL;
1,980✔
4103
        char*          output = NULL;
1,980✔
4104
        char*          inputWkt = NULL;
1,980✔
4105

4106
        retCode = initCtxGeomFromText();
1,980✔
4107
        if (retCode != TSDB_CODE_SUCCESS) {
1,980✔
4108
          break;
×
4109
        }
4110

4111
        if (pDefault->nType == TSDB_DATA_TYPE_NCHAR) {
1,980✔
4112
          int32_t charLen = varDataLen(pDefault->pz);
×
4113
          inputWkt = taosMemoryCalloc(1, charLen + TSDB_NCHAR_SIZE);
×
4114
          if (inputWkt == NULL) {
×
4115
            retCode = terrno;
×
4116
            break;
×
4117
          }
4118

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

4136
        retCode = doGeomFromText(inputWkt, &geom, &len);
1,980✔
4137
        taosMemoryFree(inputWkt);
1,980✔
4138
        if (retCode != TSDB_CODE_SUCCESS) {
1,980✔
4139
          break;
×
4140
        }
4141

4142
        output = taosMemoryCalloc(1, len + VARSTR_HEADER_SIZE);
1,980✔
4143
        if (output == NULL) {
1,980✔
4144
          geosFreeBuffer(geom);
×
4145
          retCode = terrno;
×
4146
          break;
×
4147
        }
4148

4149
        (void)memcpy(output + VARSTR_HEADER_SIZE, geom, len);
1,980✔
4150
        varDataSetLen(output, len);
1,980✔
4151
        geosFreeBuffer(geom);
1,980✔
4152

4153
        retCode = colDataSetVal(pOutput, pos, output, false);
1,980✔
4154
        taosMemoryFree(output);
1,980✔
4155
        break;
1,980✔
4156
#else
4157
        retCode = TSDB_CODE_FUNC_FUNTION_PARA_TYPE;
4158
        break;
4159
#endif
4160
      }
4161

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

4181
  return retCode;
14,004,894✔
4182
}
4183

4184
static int32_t cloneLagLeadRowValue(const SLagLeadRowValue* pSrc, SLagLeadRowValue* pDst) {
12,200,487✔
4185
  pDst->isDataNull = pSrc->isDataNull;
12,200,487✔
4186
  pDst->pData = NULL;
12,200,487✔
4187
  pDst->dataLen = pSrc->dataLen;
12,200,487✔
4188
  pDst->block = pSrc->block;
12,200,487✔
4189
  pDst->rowIndex = pSrc->rowIndex;
12,200,487✔
4190

4191
  if (pSrc->isDataNull || pSrc->pData == NULL) {
12,200,487✔
4192
    return TSDB_CODE_SUCCESS;
990✔
4193
  }
4194

4195
  int32_t dataLen = pSrc->dataLen;
12,199,497✔
4196

4197
  if (dataLen <= 0) {
12,199,497✔
4198
    return TSDB_CODE_SUCCESS;
×
4199
  }
4200

4201
  pDst->pData = taosMemoryMalloc(dataLen);
12,199,497✔
4202
  if (pDst->pData == NULL) {
12,199,497✔
4203
    return terrno;
×
4204
  }
4205

4206
  (void)memcpy(pDst->pData, pSrc->pData, dataLen);
12,199,497✔
4207
  return TSDB_CODE_SUCCESS;
12,199,497✔
4208
}
4209

4210
static int32_t setLagLeadOutputFromValue(SqlFunctionCtx* pCtx, int32_t pos, SLagLeadRowValue* pValue) {
31,604,842✔
4211
  if (pValue->isDataNull) {
31,604,842✔
4212
    colDataSetNULL((SColumnInfoData*)pCtx->pOutput, pos);
2,970✔
4213
    return TSDB_CODE_SUCCESS;
2,970✔
4214
  }
4215

4216
  return colDataSetVal((SColumnInfoData*)pCtx->pOutput, pos, pValue->pData, false);
31,601,872✔
4217
}
4218

4219
static int32_t resolveLeadPendingRows(SqlFunctionCtx* pCtx, SLagLeadState* pState, SArray* pCurrValues) {
39,962✔
4220
  if (pState->pLeadPending == NULL || taosArrayGetSize(pState->pLeadPending) == 0) {
39,962✔
4221
    return TSDB_CODE_SUCCESS;
36,002✔
4222
  }
4223

4224
  int32_t code = TSDB_CODE_SUCCESS;
3,960✔
4225
  int32_t currSize = taosArrayGetSize(pCurrValues);
3,960✔
4226
  int32_t pendingSize = taosArrayGetSize(pState->pLeadPending);
3,960✔
4227
  SArray* pRemain = taosArrayInit(TMAX(pendingSize, 1), sizeof(SLeadPendingItem));
3,960✔
4228
  if (pRemain == NULL) {
3,960✔
4229
    return terrno;
×
4230
  }
4231

4232
  for (int32_t i = 0; i < pendingSize; ++i) {
8,116,515✔
4233
    SLeadPendingItem* pItem = taosArrayGet(pState->pLeadPending, i);
8,112,555✔
4234
    if (pItem == NULL) {
8,112,555✔
4235
      code = terrno;
×
4236
      goto cleanup;
×
4237
    }
4238

4239
    if (pItem->needIdx < currSize) {
8,112,555✔
4240
      SLagLeadRowValue* pTarget = taosArrayGet(pCurrValues, pItem->needIdx);
5,846,445✔
4241
      if (pTarget == NULL) {
5,846,445✔
4242
        code = terrno;
×
4243
        goto cleanup;
×
4244
      }
4245

4246
      code = setLagLeadOutputFromValue(pCtx, pItem->outputPos, pTarget);
5,846,445✔
4247
      if (code != TSDB_CODE_SUCCESS) {
5,846,445✔
4248
        goto cleanup;
×
4249
      }
4250
    } else {
4251
      pItem->needIdx -= currSize;
2,266,110✔
4252
      if (NULL == taosArrayPush(pRemain, pItem)) {
2,266,110✔
4253
        code = terrno;
×
4254
        goto cleanup;
×
4255
      }
4256
    }
4257
  }
4258

4259
  taosArrayDestroy(pState->pLeadPending);
3,960✔
4260
  pState->pLeadPending = pRemain;
3,960✔
4261

4262
cleanup:
3,960✔
4263
  if (code != TSDB_CODE_SUCCESS) {
3,960✔
4264
    taosArrayDestroy(pRemain);
×
4265
  }
4266

4267
  return code;
3,960✔
4268
}
4269

4270
static int32_t refreshLagTailValues(SLagLeadState* pState, SArray* pCurrValues, int64_t offset) {
31,952✔
4271
  int32_t currSize = taosArrayGetSize(pCurrValues);
31,952✔
4272
  if (offset <= 0 || currSize <= 0) {
31,952✔
4273
    return TSDB_CODE_SUCCESS;
×
4274
  }
4275

4276
  int32_t oldSize = (pState->pLagTail == NULL) ? 0 : taosArrayGetSize(pState->pLagTail);
31,952✔
4277
  int32_t keep = (int32_t)TMIN(offset, oldSize + currSize);
31,952✔
4278

4279
  SArray* pNewTail = taosArrayInit(TMAX(keep, 1), sizeof(SLagLeadRowValue));
31,952✔
4280
  if (pNewTail == NULL) {
31,952✔
4281
    return terrno;
×
4282
  }
4283

4284
  int32_t start = oldSize + currSize - keep;
31,952✔
4285
  for (int32_t idx = start; idx < oldSize + currSize; ++idx) {
12,232,439✔
4286
    SLagLeadRowValue* pSrc = NULL;
12,200,487✔
4287
    if (idx < oldSize) {
12,200,487✔
4288
      pSrc = taosArrayGet(pState->pLagTail, idx);
2,266,110✔
4289
    } else {
4290
      pSrc = taosArrayGet(pCurrValues, idx - oldSize);
9,934,377✔
4291
    }
4292

4293
    if (pSrc == NULL) {
12,200,487✔
4294
      cleanupLagLeadRowValueArray(pNewTail);
×
4295
      return terrno;
×
4296
    }
4297

4298
    SLagLeadRowValue newVal = {0};
12,200,487✔
4299
    int32_t code = cloneLagLeadRowValue(pSrc, &newVal);
12,200,487✔
4300
    if (code != TSDB_CODE_SUCCESS) {
12,200,487✔
4301
      cleanupLagLeadRowValueArray(pNewTail);
×
4302
      return code;
×
4303
    }
4304

4305
    if (NULL == taosArrayPush(pNewTail, &newVal)) {
12,200,487✔
4306
      if (newVal.pData != NULL) {
×
4307
        taosMemoryFree(newVal.pData);
×
4308
      }
4309
      cleanupLagLeadRowValueArray(pNewTail);
×
4310
      return terrno;
×
4311
    }
4312
  }
4313

4314
  if (pState->pLagTail != NULL) {
31,952✔
4315
    cleanupLagLeadRowValueArray(pState->pLagTail);
3,960✔
4316
  }
4317
  pState->pLagTail = pNewTail;
31,952✔
4318
  return TSDB_CODE_SUCCESS;
31,952✔
4319
}
4320

4321
static int32_t lagLeadFunctionByRowImpl(SArray* pCtxArray, bool isLead) {
68,699✔
4322
  int32_t code = TSDB_CODE_SUCCESS;
68,699✔
4323
  int32_t colNum = pCtxArray->size;
68,699✔
4324
  if (colNum == 0) {
68,699✔
4325
    return TSDB_CODE_SUCCESS;
×
4326
  }
4327

4328
  int32_t numOfElems = 0;
68,699✔
4329
  SArray* pRows = taosArrayInit_s(sizeof(SFuncInputRow), colNum);
68,699✔
4330
  if (NULL == pRows) {
68,699✔
4331
    return terrno;
×
4332
  }
4333

4334
  SArray* pValueArrays = taosArrayInit(colNum, sizeof(SArray*));
68,699✔
4335
  if (NULL == pValueArrays) {
68,699✔
4336
    code = terrno;
×
4337
    goto _exit;
×
4338
  }
4339

4340
  for (int32_t i = 0; i < colNum; ++i) {
140,613✔
4341
    SArray* pValues = taosArrayInit(32, sizeof(SLagLeadRowValue));
71,914✔
4342
    if (NULL == pValues) {
71,914✔
4343
      code = terrno;
×
4344
      goto _exit;
×
4345
    }
4346

4347
    if (NULL == taosArrayPush(pValueArrays, &pValues)) {
71,914✔
4348
      cleanupLagLeadRowValueArray(pValues);
×
4349
      code = terrno;
×
4350
      goto _exit;
×
4351
    }
4352
  }
4353

4354
  for (int32_t i = 0; i < colNum; ++i) {
140,613✔
4355
    SqlFunctionCtx* pCtx = *(SqlFunctionCtx**)taosArrayGet(pCtxArray, i);
71,914✔
4356
    if (NULL == pCtx) {
71,914✔
4357
      code = terrno;
×
4358
      goto _exit;
×
4359
    }
4360
    funcInputUpdate(pCtx);
71,914✔
4361
  }
4362

4363
  SqlFunctionCtx* pCtx0 = *(SqlFunctionCtx**)taosArrayGet(pCtxArray, 0);
68,699✔
4364
  SFuncInputRow*  pRow0 = (SFuncInputRow*)taosArrayGet(pRows, 0);
68,699✔
4365
  if (NULL == pCtx0 || NULL == pRow0) {
68,699✔
4366
    code = terrno;
×
4367
    goto _exit;
×
4368
  }
4369

4370
  int32_t startOffset = pCtx0->offset;
68,699✔
4371
  bool    result = false;
68,699✔
4372
  while (1) {
4373
    code = funcInputGetNextRow(pCtx0, pRow0, &result);
39,843,320✔
4374
    if (TSDB_CODE_SUCCESS != code) {
39,843,320✔
4375
      goto _exit;
×
4376
    }
4377
    if (!result) {
39,843,320✔
4378
      break;
68,699✔
4379
    }
4380

4381
    {
4382
      SArray*          pValues0 = *(SArray**)taosArrayGet(pValueArrays, 0);
39,774,621✔
4383
      SLagLeadRowValue rowValue = {0};
39,774,621✔
4384
      code = copyLagLeadRowValue(pCtx0, pRow0, &rowValue);
39,774,621✔
4385
      if (code != TSDB_CODE_SUCCESS) {
39,774,621✔
4386
        goto _exit;
×
4387
      }
4388

4389
      if (NULL == taosArrayPush(pValues0, &rowValue)) {
39,774,621✔
4390
        if (rowValue.pData != NULL) {
×
4391
          taosMemoryFree(rowValue.pData);
×
4392
        }
4393
        code = terrno;
×
4394
        goto _exit;
×
4395
      }
4396
    }
4397

4398
    for (int32_t i = 1; i < colNum; ++i) {
39,788,716✔
4399
      SqlFunctionCtx* pCtx = *(SqlFunctionCtx**)taosArrayGet(pCtxArray, i);
14,095✔
4400
      SFuncInputRow*  pRow = (SFuncInputRow*)taosArrayGet(pRows, i);
14,095✔
4401
      if (NULL == pCtx || NULL == pRow) {
14,095✔
4402
        code = terrno;
×
4403
        goto _exit;
×
4404
      }
4405

4406
      code = funcInputGetNextRow(pCtx, pRow, &result);
14,095✔
4407
      if (TSDB_CODE_SUCCESS != code) {
14,095✔
4408
        goto _exit;
×
4409
      }
4410
      if (!result) {
14,095✔
4411
        code = TSDB_CODE_QRY_EXECUTOR_INTERNAL_ERROR;
×
4412
        goto _exit;
×
4413
      }
4414

4415
      SArray*          pValues = *(SArray**)taosArrayGet(pValueArrays, i);
14,095✔
4416
      SLagLeadRowValue rowValue = {0};
14,095✔
4417
      code = copyLagLeadRowValue(pCtx, pRow, &rowValue);
14,095✔
4418
      if (code != TSDB_CODE_SUCCESS) {
14,095✔
4419
        goto _exit;
×
4420
      }
4421

4422
      if (NULL == taosArrayPush(pValues, &rowValue)) {
14,095✔
4423
        if (rowValue.pData != NULL) {
×
4424
          taosMemoryFree(rowValue.pData);
×
4425
        }
4426
        code = terrno;
×
4427
        goto _exit;
×
4428
      }
4429
    }
4430

4431
    ++numOfElems;
39,774,621✔
4432
  }
4433

4434
  for (int32_t i = 0; i < colNum; ++i) {
140,613✔
4435
    SqlFunctionCtx* pCtx = *(SqlFunctionCtx**)taosArrayGet(pCtxArray, i);
71,914✔
4436
    SArray*         pValues = *(SArray**)taosArrayGet(pValueArrays, i);
71,914✔
4437
    if (NULL == pCtx || NULL == pValues) {
71,914✔
4438
      code = terrno;
×
4439
      goto _exit;
×
4440
    }
4441

4442
    SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
71,914✔
4443
    SLagLeadState*       pState = GET_ROWCELL_INTERBUF(pResInfo);
71,914✔
4444
    if (pState == NULL) {
71,914✔
4445
      code = terrno;
×
4446
      goto _exit;
×
4447
    }
4448

4449
    int64_t offset = pCtx->param[1].param.i;
71,914✔
4450
    if (offset <= 0) {
71,914✔
4451
      code = TSDB_CODE_QRY_EXECUTOR_INTERNAL_ERROR;
×
4452
      goto _exit;
×
4453
    }
4454

4455
    if (isLead) {
71,914✔
4456
      if (pState->pLeadPending == NULL) {
39,962✔
4457
        pState->pLeadPending = taosArrayInit(8, sizeof(SLeadPendingItem));
36,002✔
4458
        if (pState->pLeadPending == NULL) {
36,002✔
4459
          code = terrno;
×
4460
          goto _exit;
×
4461
        }
4462
      }
4463

4464
      code = resolveLeadPendingRows(pCtx, pState, pValues);
39,962✔
4465
      if (code != TSDB_CODE_SUCCESS) {
39,962✔
4466
        goto _exit;
×
4467
      }
4468
    }
4469

4470
    for (int32_t rowIdx = 0; rowIdx < numOfElems; ++rowIdx) {
39,860,630✔
4471
      int32_t pos = startOffset + rowIdx;
39,788,716✔
4472
      SLagLeadRowValue* pCurRowValue = taosArrayGet(pValues, rowIdx);
39,788,716✔
4473
      if (pCurRowValue == NULL) {
39,788,716✔
4474
        code = terrno;
×
4475
        goto _exit;
×
4476
      }
4477

4478
      if (isLead) {
39,788,716✔
4479
        int64_t targetIdx = (int64_t)rowIdx + offset;
19,910,823✔
4480
        if (targetIdx < numOfElems) {
19,910,823✔
4481
          SLagLeadRowValue* pTargetRowValue = taosArrayGet(pValues, targetIdx);
9,968,436✔
4482
          if (pTargetRowValue == NULL) {
9,968,436✔
4483
            code = terrno;
×
4484
            goto _exit;
×
4485
          }
4486
          code = setLagLeadOutputFromValue(pCtx, pos, pTargetRowValue);
9,968,436✔
4487
        } else {
4488
          code = setLagLeadDefaultValue(pCtx, pos);
9,942,387✔
4489
          if (code == TSDB_CODE_SUCCESS) {
9,942,387✔
4490
            SLeadPendingItem pending = {.outputPos = pos, .needIdx = targetIdx - numOfElems};
9,942,387✔
4491
            if (NULL == taosArrayPush(pState->pLeadPending, &pending)) {
19,884,774✔
4492
              code = terrno;
×
4493
            }
4494
          }
4495
        }
4496
      } else {
4497
        int64_t targetIdx = (int64_t)rowIdx - offset;
19,877,893✔
4498
        if (targetIdx >= 0) {
19,877,893✔
4499
          SLagLeadRowValue* pTargetRowValue = taosArrayGet(pValues, targetIdx);
9,943,516✔
4500
          if (pTargetRowValue == NULL) {
9,943,516✔
4501
            code = terrno;
×
4502
            goto _exit;
×
4503
          }
4504
          code = setLagLeadOutputFromValue(pCtx, pos, pTargetRowValue);
9,943,516✔
4505
        } else {
4506
          int32_t tailSize = (pState->pLagTail == NULL) ? 0 : taosArrayGetSize(pState->pLagTail);
9,934,377✔
4507
          int64_t tailIdx = tailSize + targetIdx;
9,934,377✔
4508
          if (tailIdx >= 0 && tailIdx < tailSize) {
15,780,822✔
4509
            SLagLeadRowValue* pTargetRowValue = taosArrayGet(pState->pLagTail, tailIdx);
5,846,445✔
4510
            if (pTargetRowValue == NULL) {
5,846,445✔
4511
              code = terrno;
×
4512
              goto _exit;
×
4513
            }
4514
            code = setLagLeadOutputFromValue(pCtx, pos, pTargetRowValue);
5,846,445✔
4515
          } else {
4516
            code = setLagLeadDefaultValue(pCtx, pos);
4,087,932✔
4517
          }
4518
        }
4519
      }
4520

4521
      if (code != TSDB_CODE_SUCCESS) {
39,788,716✔
4522
        goto _exit;
×
4523
      }
4524

4525
      if (pCtx->subsidiaries.num > 0) {
39,788,716✔
4526
        code = appendSelectivityCols(pCtx, pCurRowValue->block, pCurRowValue->rowIndex, pos);
19,909,080✔
4527
        if (code != TSDB_CODE_SUCCESS) {
19,909,080✔
4528
          goto _exit;
×
4529
        }
4530
      }
4531
    }
4532

4533
    if (!isLead) {
71,914✔
4534
      code = refreshLagTailValues(pState, pValues, offset);
31,952✔
4535
      if (code != TSDB_CODE_SUCCESS) {
31,952✔
4536
        goto _exit;
×
4537
      }
4538
    }
4539
  }
4540

4541
_exit:
68,699✔
4542
  for (int32_t i = 0; i < colNum; ++i) {
140,613✔
4543
    SqlFunctionCtx* pCtx = *(SqlFunctionCtx**)taosArrayGet(pCtxArray, i);
71,914✔
4544
    if (!pCtx) {
71,914✔
4545
      break;
×
4546
    }
4547

4548
    if (!code) {
71,914✔
4549
      SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
71,914✔
4550
      pResInfo->numOfRes = numOfElems;
71,914✔
4551
    }
4552
  }
4553

4554
  if (pRows) {
68,699✔
4555
    taosArrayDestroy(pRows);
68,699✔
4556
    pRows = NULL;
68,699✔
4557
  }
4558

4559
  cleanupLagLeadValueArrays(pValueArrays);
68,699✔
4560

4561
  return code;
68,699✔
4562
}
4563

4564
int32_t lagFunctionByRow(SArray* pCtxArray) {
31,012✔
4565
  return lagLeadFunctionByRowImpl(pCtxArray, false);
31,012✔
4566
}
4567

4568
bool getLeadFuncEnv(SFunctionNode* UNUSED_PARAM(pFunc), SFuncExecEnv* pEnv) {
31,200✔
4569
  pEnv->calcMemSize = sizeof(SLagLeadState);
31,200✔
4570
  return true;
31,200✔
4571
}
4572

4573
int32_t leadFunctionSetup(SqlFunctionCtx* pCtx, SResultRowEntryInfo* pResInfo) {
75,519✔
4574
  if (pResInfo->initialized) {
75,519✔
4575
    return TSDB_CODE_SUCCESS;
38,527✔
4576
  }
4577
  if (TSDB_CODE_SUCCESS != functionSetup(pCtx, pResInfo)) {
36,992✔
4578
    return TSDB_CODE_FUNC_SETUP_ERROR;
×
4579
  }
4580

4581
  SLagLeadState* pState = GET_ROWCELL_INTERBUF(pResInfo);
36,992✔
4582
  if (pState != NULL) {
36,992✔
4583
    pState->pLagTail = NULL;
36,992✔
4584
    pState->pLeadPending = NULL;
36,992✔
4585
  }
4586

4587
  return TSDB_CODE_SUCCESS;
36,992✔
4588
}
4589

4590
int32_t leadFunction(SqlFunctionCtx* UNUSED_PARAM(pCtx)) { return TSDB_CODE_SUCCESS; }
39,962✔
4591

4592
int32_t leadFunctionByRow(SArray* pCtxArray) {
37,687✔
4593
  return lagLeadFunctionByRowImpl(pCtxArray, true);
37,687✔
4594
}
4595

4596
void lagLeadFunctionCleanupExt(SqlFunctionCtx* pCtx) {
71,774✔
4597
  if (pCtx == NULL || pCtx->resultInfo == NULL) {
71,774✔
4598
    return;
5,800✔
4599
  }
4600

4601
  SLagLeadState* pState = GET_ROWCELL_INTERBUF(pCtx->resultInfo);
65,974✔
4602
  if (pState == NULL) {
65,974✔
4603
    return;
×
4604
  }
4605

4606
  if (pState->pLagTail != NULL) {
65,974✔
4607
    cleanupLagLeadRowValueArray(pState->pLagTail);
27,992✔
4608
    pState->pLagTail = NULL;
27,992✔
4609
  }
4610

4611
  if (pState->pLeadPending != NULL) {
65,974✔
4612
    taosArrayDestroy(pState->pLeadPending);
36,002✔
4613
    pState->pLeadPending = NULL;
36,002✔
4614
  }
4615
}
4616

4617
bool getFillforwardFuncEnv(SFunctionNode* UNUSED_PARAM(pFunc), SFuncExecEnv* pEnv) {
40,366✔
4618
  pEnv->calcMemSize = sizeof(SFillforwardInfo);
40,366✔
4619
  return true;
40,366✔
4620
}
4621

4622
int32_t fillforwardFunctionSetup(SqlFunctionCtx* pCtx, SResultRowEntryInfo* pResInfo) {
83,618✔
4623
  if (pResInfo->initialized) {
83,618✔
4624
    return TSDB_CODE_SUCCESS;
40,366✔
4625
  }
4626
  if (TSDB_CODE_SUCCESS != functionSetup(pCtx, pResInfo)) {
43,252✔
4627
    return TSDB_CODE_FUNC_SETUP_ERROR;
×
4628
  }
4629
  SFillforwardInfo* pFillforwardInfo = GET_ROWCELL_INTERBUF(pResInfo);
43,252✔
4630
  pFillforwardInfo->nonnull = false;
43,252✔
4631

4632
  return TSDB_CODE_SUCCESS;
43,252✔
4633
}
4634

4635
int32_t fillforwardFunction(SqlFunctionCtx* pCtx) { return TSDB_CODE_SUCCESS; }
43,252✔
4636

4637
static int32_t doHandleFillforward(SFillforwardInfo* pFillforwardInfo, int32_t type, SColumnInfoData* pOutput, int32_t pos) {
140,300✔
4638
  if (!pFillforwardInfo->nonnull) {
140,300✔
4639
    colDataSetNULL(pOutput, pos);
15,873✔
4640

4641
    return TSDB_CODE_SUCCESS;
15,873✔
4642
  }
4643

4644
  switch (type) {
124,427✔
4645
    case TSDB_DATA_TYPE_BOOL:
59,973✔
4646
    case TSDB_DATA_TYPE_UTINYINT:
4647
    case TSDB_DATA_TYPE_TINYINT:
4648
    case TSDB_DATA_TYPE_USMALLINT:
4649
    case TSDB_DATA_TYPE_SMALLINT:
4650
    case TSDB_DATA_TYPE_UINT:
4651
    case TSDB_DATA_TYPE_INT:
4652
    case TSDB_DATA_TYPE_UBIGINT:
4653
    case TSDB_DATA_TYPE_BIGINT:
4654
    case TSDB_DATA_TYPE_TIMESTAMP:
4655
      colDataSetInt64(pOutput, pos, &pFillforwardInfo->v);
59,973✔
4656
      break;
59,973✔
4657
    case TSDB_DATA_TYPE_FLOAT:
23,088✔
4658
      colDataSetFloat(pOutput, pos, &pFillforwardInfo->fv);
23,088✔
4659
      break;
23,088✔
4660
    case TSDB_DATA_TYPE_DOUBLE:
25,974✔
4661
      colDataSetDouble(pOutput, pos, &pFillforwardInfo->dv);
25,974✔
4662
      break;
25,974✔
4663
    case TSDB_DATA_TYPE_DECIMAL64:
5,291✔
4664
      return colDataSetVal(pOutput, pos, (const char*)&pFillforwardInfo->v, false);
5,291✔
4665
    case TSDB_DATA_TYPE_DECIMAL:
×
4666
      return colDataSetVal(pOutput, pos, (void*)pFillforwardInfo->dec, false);
×
4667
    case TSDB_DATA_TYPE_VARCHAR:
10,101✔
4668
    case TSDB_DATA_TYPE_VARBINARY:
4669
    case TSDB_DATA_TYPE_NCHAR:
4670
      return colDataSetVal(pOutput, pos, (void*)pFillforwardInfo->str, false);
10,101✔
4671
    default:
×
4672
      return TSDB_CODE_FUNC_FUNTION_PARA_TYPE;
×
4673
  }
4674

4675
  return TSDB_CODE_SUCCESS;
109,035✔
4676
}
4677

4678
static int32_t setFillforwardResult(SqlFunctionCtx* pCtx, SFuncInputRow* pRow, int32_t pos) {
140,300✔
4679
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
140,300✔
4680
  SFillforwardInfo*            pFillforwardInfo = GET_ROWCELL_INTERBUF(pResInfo);
140,300✔
4681

4682
  SInputColumnInfoData* pInput = &pCtx->input;
140,300✔
4683
  SColumnInfoData*      pInputCol = pInput->pData[0];
140,300✔
4684
  int8_t                inputType = pInputCol->info.type;
140,300✔
4685
  SColumnInfoData*      pOutput = (SColumnInfoData*)pCtx->pOutput;
140,300✔
4686
  int32_t               code = TSDB_CODE_SUCCESS;
140,300✔
4687

4688
  code = doHandleFillforward(pFillforwardInfo, inputType, pOutput, pos);
140,300✔
4689
  if (code != TSDB_CODE_SUCCESS) {
140,300✔
4690
    return code;
×
4691
  }
4692

4693
  // handle selectivity
4694
  if (pCtx->subsidiaries.num > 0) {
140,300✔
4695
    code = appendSelectivityCols(pCtx, pRow->block, pRow->rowIndex, pos);
38,328✔
4696
    if (code != TSDB_CODE_SUCCESS) {
38,328✔
4697
      return code;
×
4698
    }
4699
  }
4700

4701
  return TSDB_CODE_SUCCESS;
140,300✔
4702
}
4703

4704
int32_t fillforwardFunctionByRow(SArray* pCtxArray) {
12,468✔
4705
  int32_t code = TSDB_CODE_SUCCESS;
12,468✔
4706
  int     fillforwardColNum = pCtxArray->size;
12,468✔
4707
  if (fillforwardColNum == 0) {
12,468✔
4708
    return TSDB_CODE_SUCCESS;
×
4709
  }
4710
  int32_t numOfElems = 0;
12,468✔
4711

4712
  SArray* pRows = taosArrayInit_s(sizeof(SFuncInputRow), fillforwardColNum);
12,468✔
4713
  if (NULL == pRows) {
12,468✔
4714
    return terrno;
×
4715
  }
4716

4717
  for (int i = 0; i < fillforwardColNum; ++i) {
55,720✔
4718
    SqlFunctionCtx* pCtx = *(SqlFunctionCtx**)taosArrayGet(pCtxArray, i);
43,252✔
4719
    if (NULL == pCtx) {
43,252✔
4720
      code = terrno;
×
4721
      goto _exit;
×
4722
    }
4723
    funcInputUpdate(pCtx);
43,252✔
4724
  }
4725

4726
  SqlFunctionCtx* pCtx0 = *(SqlFunctionCtx**)taosArrayGet(pCtxArray, 0);
12,468✔
4727
  SFuncInputRow*  pRow0 = (SFuncInputRow*)taosArrayGet(pRows, 0);
12,468✔
4728
  if (NULL == pCtx0 || NULL == pRow0) {
12,468✔
4729
    code = terrno;
×
4730
    goto _exit;
×
4731
  }
4732
  int32_t startOffset = pCtx0->offset;
12,468✔
4733
  bool    result = false;
12,468✔
4734
  while (1) {
38,328✔
4735
    code = funcInputGetNextRow(pCtx0, pRow0, &result);
50,796✔
4736
    if (TSDB_CODE_SUCCESS != code) {
50,796✔
4737
      goto _exit;
×
4738
    }
4739
    if (!result) {
50,796✔
4740
      break;
11,987✔
4741
    }
4742

4743
    for (int i = 1; i < fillforwardColNum; ++i) {
140,781✔
4744
      SqlFunctionCtx* pCtx = *(SqlFunctionCtx**)taosArrayGet(pCtxArray, i);
101,972✔
4745
      SFuncInputRow*  pRow = (SFuncInputRow*)taosArrayGet(pRows, i);
101,972✔
4746
      if (NULL == pCtx || NULL == pRow) {
101,972✔
4747
        code = terrno;
×
4748
        goto _exit;
×
4749
      }
4750
      code = funcInputGetNextRow(pCtx, pRow, &result);
101,972✔
4751
      if (TSDB_CODE_SUCCESS != code) {
101,972✔
4752
        goto _exit;
×
4753
      }
4754
      if (!result) {
101,972✔
4755
        // rows are not equal
4756
        code = TSDB_CODE_QRY_EXECUTOR_INTERNAL_ERROR;
×
4757
        goto _exit;
×
4758
      }
4759
    }
4760

4761
    int32_t pos = startOffset + numOfElems;
38,809✔
4762

4763
    for (int i = 0; i < fillforwardColNum; ++i) {
179,109✔
4764
      SqlFunctionCtx* pCtx = *(SqlFunctionCtx**)taosArrayGet(pCtxArray, i);
140,781✔
4765
      SFuncInputRow*  pRow = (SFuncInputRow*)taosArrayGet(pRows, i);
140,781✔
4766
      if (NULL == pCtx || NULL == pRow) {
140,781✔
4767
        code = terrno;
×
4768
        goto _exit;
×
4769
      }
4770

4771
      if (!colDataIsNull_s(pCtx->input.pData[0], pCtx->rowIter.rowIndex - 1)) {
281,562✔
4772
        SResultRowEntryInfo*  pResInfo = GET_RES_INFO(pCtx);
86,428✔
4773
        SFillforwardInfo*             pFillforwardInfo = GET_ROWCELL_INTERBUF(pResInfo);
86,428✔
4774
        SInputColumnInfoData* pInput = &pCtx->input;
86,428✔
4775
        SColumnInfoData*      pInputCol = pInput->pData[0];
86,428✔
4776
        int8_t                inputType = pInputCol->info.type;
86,428✔
4777

4778
        char* pv = pRow->pData;
86,428✔
4779
        switch (inputType) {
86,428✔
4780
          case TSDB_DATA_TYPE_BOOL:
16,835✔
4781
            pFillforwardInfo->v = *(bool*)pv ? 1 : 0;
16,835✔
4782
            break;
16,835✔
4783
          case TSDB_DATA_TYPE_UTINYINT:
481✔
4784
          case TSDB_DATA_TYPE_TINYINT:
4785
            pFillforwardInfo->v = *(int8_t*)pv;
481✔
4786
            break;
481✔
4787
          case TSDB_DATA_TYPE_UINT:
24,860✔
4788
          case TSDB_DATA_TYPE_INT:
4789
            pFillforwardInfo->v = *(int32_t*)pv;
24,860✔
4790
            break;
24,860✔
4791
          case TSDB_DATA_TYPE_USMALLINT:
481✔
4792
          case TSDB_DATA_TYPE_SMALLINT:
4793
            pFillforwardInfo->v = *(int16_t*)pv;
481✔
4794
            break;
481✔
4795
          case TSDB_DATA_TYPE_TIMESTAMP:
481✔
4796
          case TSDB_DATA_TYPE_UBIGINT:
4797
          case TSDB_DATA_TYPE_BIGINT:
4798
            pFillforwardInfo->v = *(int64_t*)pv;
481✔
4799
            break;
481✔
4800
          case TSDB_DATA_TYPE_FLOAT:
16,835✔
4801
            pFillforwardInfo->fv = *(float*)pv;
16,835✔
4802
            break;
16,835✔
4803
          case TSDB_DATA_TYPE_DOUBLE:
18,759✔
4804
            pFillforwardInfo->dv = *(double*)pv;
18,759✔
4805
            break;
18,759✔
4806
          case TSDB_DATA_TYPE_DECIMAL64:
2,886✔
4807
            DECIMAL64_SET_VALUE((Decimal64*)&pFillforwardInfo->v, *(int64_t*)pv);
2,886✔
4808
            break;
2,886✔
4809
          case TSDB_DATA_TYPE_DECIMAL:
×
4810
            DECIMAL128_CLONE((Decimal128*)pFillforwardInfo->dec, (Decimal128*)pv);
×
4811
            break;
×
4812
          case TSDB_DATA_TYPE_VARCHAR:
4,329✔
4813
          case TSDB_DATA_TYPE_VARBINARY:
4814
          case TSDB_DATA_TYPE_NCHAR: {
4815
            if (!pFillforwardInfo->nonnull) {
4,329✔
4816
              pFillforwardInfo->str = taosMemoryMalloc(pInputCol->info.bytes);
2,886✔
4817
              if (!pFillforwardInfo->str) {
2,886✔
4818
                code = terrno;
×
4819
                goto _exit;
×
4820
              }
4821
            }
4822

4823
            (void)memcpy(pFillforwardInfo->str, pv, varDataTLen(pv));
4,329✔
4824
          } break;
4,329✔
4825
          default: {
481✔
4826
            code = TSDB_CODE_FUNC_FUNTION_PARA_TYPE;
481✔
4827
            goto _exit;
481✔
4828
          }
4829
        }
4830

4831
        if (!pFillforwardInfo->nonnull) {
85,947✔
4832
          pFillforwardInfo->nonnull = true;
42,290✔
4833
        }
4834
      }
4835

4836
      code = setFillforwardResult(pCtx, pRow, pos);
140,300✔
4837
      if (code) {
140,300✔
4838
        goto _exit;
×
4839
      }
4840
    }
4841

4842
    ++numOfElems;
38,328✔
4843
  }
4844

4845
_exit:
12,468✔
4846
  for (int i = 0; i < fillforwardColNum; ++i) {
55,720✔
4847
    SqlFunctionCtx* pCtx = *(SqlFunctionCtx**)taosArrayGet(pCtxArray, i);
43,252✔
4848
    if (!pCtx) {
43,252✔
4849
      break;
×
4850
    }
4851

4852
    SResultRowEntryInfo*  pResInfo = GET_RES_INFO(pCtx);
43,252✔
4853
    SFillforwardInfo*             pRes = GET_ROWCELL_INTERBUF(pResInfo);
43,252✔
4854
    SInputColumnInfoData* pInput = &pCtx->input;
43,252✔
4855
    SColumnInfoData*      pInputCol = pInput->pData[0];
43,252✔
4856

4857
    if (IS_VAR_DATA_TYPE(pInputCol->info.type) && pRes->nonnull) {
43,252✔
4858
      taosMemoryFree(pRes->str);
2,886✔
4859
    }
4860

4861
    if (!code) {
43,252✔
4862
      pResInfo->numOfRes = numOfElems;
42,771✔
4863
    }
4864
  }
4865

4866
  if (pRows) {
12,468✔
4867
    taosArrayDestroy(pRows);
12,468✔
4868
    pRows = NULL;
12,468✔
4869
  }
4870
  return code;
12,468✔
4871
}
4872

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

4875
bool getTopBotFuncEnv(SFunctionNode* pFunc, SFuncExecEnv* pEnv) {
2,268,612✔
4876
  SValueNode* pkNode = (SValueNode*)nodesListGetNode(pFunc->pParameterList, 1);
2,268,612✔
4877
  pEnv->calcMemSize = sizeof(STopBotRes) + pkNode->datum.i * sizeof(STopBotResItem);
2,272,043✔
4878
  return true;
2,270,442✔
4879
}
4880

4881
int32_t topBotFunctionSetup(SqlFunctionCtx* pCtx, SResultRowEntryInfo* pResInfo) {
8,470,818✔
4882
  if (pResInfo->initialized) {
8,470,818✔
4883
    return TSDB_CODE_SUCCESS;
×
4884
  }
4885
  if (TSDB_CODE_SUCCESS != functionSetup(pCtx, pResInfo)) {
8,471,536✔
4886
    return TSDB_CODE_FUNC_SETUP_ERROR;
×
4887
  }
4888

4889
  STopBotRes*           pRes = GET_ROWCELL_INTERBUF(pResInfo);
8,471,060✔
4890
  SInputColumnInfoData* pInput = &pCtx->input;
8,470,100✔
4891

4892
  pRes->maxSize = pCtx->param[1].param.i;
8,471,536✔
4893

4894
  pRes->nullTupleSaved = false;
8,470,818✔
4895
  pRes->nullTuplePos.pageId = -1;
8,471,060✔
4896
  return TSDB_CODE_SUCCESS;
8,470,818✔
4897
}
4898

4899
static STopBotRes* getTopBotOutputInfo(SqlFunctionCtx* pCtx) {
2,147,483,647✔
4900
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
2,147,483,647✔
4901
  STopBotRes*          pRes = GET_ROWCELL_INTERBUF(pResInfo);
2,147,483,647✔
4902
  pRes->pItems = (STopBotResItem*)((char*)pRes + sizeof(STopBotRes));
2,147,483,647✔
4903

4904
  return pRes;
2,147,483,647✔
4905
}
4906

4907
static int32_t doAddIntoResult(SqlFunctionCtx* pCtx, void* pData, int32_t rowIndex, SSDataBlock* pSrcBlock,
4908
                               uint16_t type, uint64_t uid, SResultRowEntryInfo* pEntryInfo, bool isTopQuery);
4909

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

4912
int32_t topFunction(SqlFunctionCtx* pCtx) {
9,880,987✔
4913
  int32_t              numOfElems = 0;
9,880,987✔
4914
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
9,880,987✔
4915

4916
  SInputColumnInfoData* pInput = &pCtx->input;
9,885,882✔
4917
  SColumnInfoData*      pCol = pInput->pData[0];
9,884,592✔
4918

4919
  STopBotRes* pRes = getTopBotOutputInfo(pCtx);
9,884,487✔
4920
  pRes->type = pInput->pData[0]->info.type;
9,882,176✔
4921

4922
  int32_t start = pInput->startRowIndex;
9,885,144✔
4923
  for (int32_t i = start; i < pInput->numOfRows + start; ++i) {
1,380,394,930✔
4924
    if (pCol->hasNull && colDataIsNull_f(pCol, i)) {
1,370,499,556✔
4925
      continue;
1,365,388✔
4926
    }
4927

4928
    numOfElems++;
1,369,174,790✔
4929
    char*   data = colDataGetData(pCol, i);
1,369,174,790✔
4930
    int32_t code = doAddIntoResult(pCtx, data, i, pCtx->pSrcBlock, pRes->type, pInput->uid, pResInfo, true);
1,369,514,811✔
4931
    if (code != TSDB_CODE_SUCCESS) {
1,369,144,640✔
4932
      return code;
×
4933
    }
4934
  }
4935

4936
  if (numOfElems == 0 && pCtx->subsidiaries.num > 0 && !pRes->nullTupleSaved) {
9,887,187✔
4937
    int32_t code = saveTupleData(pCtx, pInput->startRowIndex, pCtx->pSrcBlock, &pRes->nullTuplePos);
1,725✔
4938
    if (code != TSDB_CODE_SUCCESS) {
1,725✔
4939
      return code;
×
4940
    }
4941
    pRes->nullTupleSaved = true;
1,725✔
4942
  }
4943
  return TSDB_CODE_SUCCESS;
9,885,751✔
4944
}
4945

4946
int32_t bottomFunction(SqlFunctionCtx* pCtx) {
3,508,720✔
4947
  int32_t              numOfElems = 0;
3,508,720✔
4948
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
3,508,720✔
4949

4950
  SInputColumnInfoData* pInput = &pCtx->input;
3,511,138✔
4951
  SColumnInfoData*      pCol = pInput->pData[0];
3,511,138✔
4952

4953
  STopBotRes* pRes = getTopBotOutputInfo(pCtx);
3,511,138✔
4954
  pRes->type = pInput->pData[0]->info.type;
3,510,420✔
4955

4956
  int32_t start = pInput->startRowIndex;
3,509,929✔
4957
  for (int32_t i = start; i < pInput->numOfRows + start; ++i) {
940,746,276✔
4958
    if (pCol->hasNull && colDataIsNull_f(pCol, i)) {
936,504,715✔
4959
      continue;
3,920,861✔
4960
    }
4961

4962
    numOfElems++;
932,556,574✔
4963
    char*   data = colDataGetData(pCol, i);
932,556,574✔
4964
    int32_t code = doAddIntoResult(pCtx, data, i, pCtx->pSrcBlock, pRes->type, pInput->uid, pResInfo, false);
933,780,021✔
4965
    if (code != TSDB_CODE_SUCCESS) {
933,314,995✔
4966
      return code;
×
4967
    }
4968
  }
4969

4970
  if (numOfElems == 0 && pCtx->subsidiaries.num > 0 && !pRes->nullTupleSaved) {
3,511,138✔
4971
    int32_t code = saveTupleData(pCtx, pInput->startRowIndex, pCtx->pSrcBlock, &pRes->nullTuplePos);
13,405✔
4972
    if (code != TSDB_CODE_SUCCESS) {
13,405✔
4973
      return code;
×
4974
    }
4975
    pRes->nullTupleSaved = true;
13,405✔
4976
  }
4977

4978
  return TSDB_CODE_SUCCESS;
3,510,420✔
4979
}
4980

4981
static int32_t topBotResComparFn(const void* p1, const void* p2, const void* param) {
544,240,304✔
4982
  uint16_t type = *(uint16_t*)param;
544,240,304✔
4983

4984
  STopBotResItem* val1 = (STopBotResItem*)p1;
544,250,371✔
4985
  STopBotResItem* val2 = (STopBotResItem*)p2;
544,250,371✔
4986

4987
  if (IS_SIGNED_NUMERIC_TYPE(type)) {
544,250,371✔
4988
    if (val1->v.i == val2->v.i) {
350,954,734✔
4989
      return 0;
59,793,255✔
4990
    }
4991

4992
    return (val1->v.i > val2->v.i) ? 1 : -1;
291,340,993✔
4993
  } else if (IS_UNSIGNED_NUMERIC_TYPE(type)) {
193,295,637✔
4994
    if (val1->v.u == val2->v.u) {
93,708,129✔
4995
      return 0;
19,836,216✔
4996
    }
4997

4998
    return (val1->v.u > val2->v.u) ? 1 : -1;
73,874,725✔
4999
  } else if (TSDB_DATA_TYPE_FLOAT == type) {
99,587,901✔
5000
    if (val1->v.f == val2->v.f) {
2,675,052✔
5001
      return 0;
30,870✔
5002
    }
5003

5004
    return (val1->v.f > val2->v.f) ? 1 : -1;
2,644,182✔
5005
  }
5006

5007
  if (val1->v.d == val2->v.d) {
96,912,849✔
5008
    return 0;
5,390✔
5009
  }
5010

5011
  return (val1->v.d > val2->v.d) ? 1 : -1;
96,948,327✔
5012
}
5013

5014
int32_t doAddIntoResult(SqlFunctionCtx* pCtx, void* pData, int32_t rowIndex, SSDataBlock* pSrcBlock, uint16_t type,
2,147,483,647✔
5015
                        uint64_t uid, SResultRowEntryInfo* pEntryInfo, bool isTopQuery) {
5016
  STopBotRes* pRes = getTopBotOutputInfo(pCtx);
2,147,483,647✔
5017
  int32_t     code = TSDB_CODE_SUCCESS;
2,147,483,647✔
5018

5019
  SVariant val = {0};
2,147,483,647✔
5020
  TAOS_CHECK_RETURN(taosVariantCreateFromBinary(&val, pData, tDataTypes[type].bytes, type));
2,147,483,647✔
5021

5022
  STopBotResItem* pItems = pRes->pItems;
2,147,483,647✔
5023

5024
  // not full yet
5025
  if (pEntryInfo->numOfRes < pRes->maxSize) {
2,147,483,647✔
5026
    STopBotResItem* pItem = &pItems[pEntryInfo->numOfRes];
49,039,518✔
5027
    pItem->v = val;
49,037,364✔
5028
    pItem->uid = uid;
49,040,671✔
5029

5030
    // save the data of this tuple
5031
    if (pCtx->subsidiaries.num > 0) {
49,040,808✔
5032
      code = saveTupleData(pCtx, rowIndex, pSrcBlock, &pItem->tuplePos);
13,288,121✔
5033
      if (code != TSDB_CODE_SUCCESS) {
13,285,810✔
5034
        return code;
×
5035
      }
5036
    }
5037
#ifdef BUF_PAGE_DEBUG
5038
    qDebug("page_saveTuple i:%d, item:%p,pageId:%d, offset:%d\n", pEntryInfo->numOfRes, pItem, pItem->tuplePos.pageId,
5039
           pItem->tuplePos.offset);
5040
#endif
5041
    // allocate the buffer and keep the data of this row into the new allocated buffer
5042
    pEntryInfo->numOfRes++;
49,039,084✔
5043
    code = taosheapsort((void*)pItems, sizeof(STopBotResItem), pEntryInfo->numOfRes, (const void*)&type,
49,038,315✔
5044
                        topBotResComparFn, !isTopQuery);
49,040,186✔
5045
    if (code != TSDB_CODE_SUCCESS) {
49,034,529✔
5046
      return code;
×
5047
    }
5048
  } else {  // replace the minimum value in the result
5049
    if ((isTopQuery && ((IS_SIGNED_NUMERIC_TYPE(type) && val.i > pItems[0].v.i) ||
2,147,483,647✔
5050
                        (IS_UNSIGNED_NUMERIC_TYPE(type) && val.u > pItems[0].v.u) ||
1,313,468,117✔
5051
                        (TSDB_DATA_TYPE_FLOAT == type && val.f > pItems[0].v.f) ||
1,303,748,950✔
5052
                        (TSDB_DATA_TYPE_DOUBLE == type && val.d > pItems[0].v.d))) ||
1,303,606,483✔
5053
        (!isTopQuery && ((IS_SIGNED_NUMERIC_TYPE(type) && val.i < pItems[0].v.i) ||
2,147,483,647✔
5054
                         (IS_UNSIGNED_NUMERIC_TYPE(type) && val.u < pItems[0].v.u) ||
921,119,313✔
5055
                         (TSDB_DATA_TYPE_FLOAT == type && val.f < pItems[0].v.f) ||
920,196,940✔
5056
                         (TSDB_DATA_TYPE_DOUBLE == type && val.d < pItems[0].v.d)))) {
920,117,370✔
5057
      // replace the old data and the coresponding tuple data
5058
      STopBotResItem* pItem = &pItems[0];
40,567,735✔
5059
      pItem->v = val;
40,567,735✔
5060
      pItem->uid = uid;
40,485,766✔
5061

5062
      // save the data of this tuple by over writing the old data
5063
      if (pCtx->subsidiaries.num > 0) {
40,485,290✔
5064
        code = updateTupleData(pCtx, rowIndex, pSrcBlock, &pItem->tuplePos);
21,455,718✔
5065
        if (code != TSDB_CODE_SUCCESS) {
21,456,091✔
5066
          return code;
×
5067
        }
5068
      }
5069
#ifdef BUF_PAGE_DEBUG
5070
      qDebug("page_copyTuple pageId:%d, offset:%d", pItem->tuplePos.pageId, pItem->tuplePos.offset);
5071
#endif
5072
      code = taosheapadjust((void*)pItems, sizeof(STopBotResItem), 0, pEntryInfo->numOfRes - 1, (const void*)&type,
40,484,834✔
5073
                            topBotResComparFn, NULL, !isTopQuery);
40,486,381✔
5074
      if (code != TSDB_CODE_SUCCESS) {
40,476,344✔
5075
        return code;
×
5076
      }
5077
    }
5078
  }
5079

5080
  return TSDB_CODE_SUCCESS;
2,147,483,647✔
5081
}
5082

5083

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

5089
  if (!pData->hasNull) {
×
5090
    return false;
×
5091
  }
5092

5093
  int64_t endIdx = startIdx + rows;
×
5094
  for (int64_t i = startIdx; i < endIdx; ++i) {
×
5095
    if (colDataIsNull_s(pData, i)) {
×
5096
      return true;
×
5097
    }
5098
  }
5099

5100
  return false;
×
5101
}
5102

5103

5104
/*
5105
 * +------------------------------------+--------------+--------------+
5106
 * |            null bitmap             |              |              |
5107
 * |(n columns, one bit for each column)| src column #1| src column #2|
5108
 * +------------------------------------+--------------+--------------+
5109
 */
5110
int32_t serializeTupleData(SqlFunctionCtx* pCtx, const SSDataBlock* pSrcBlock, int32_t rowIndex, SSubsidiaryResInfo* pSubsidiaryies,
122,581,480✔
5111
                           char* buf, char** res) {
5112
  char* nullList = buf;
122,581,480✔
5113
  char* pStart = (char*)(nullList + sizeof(bool) * pSubsidiaryies->num);
122,581,480✔
5114

5115
  int32_t offset = 0;
122,578,475✔
5116
  for (int32_t i = 0; i < pSubsidiaryies->num; ++i) {
383,866,282✔
5117
    SqlFunctionCtx* pc = pSubsidiaryies->pCtx[i];
261,281,472✔
5118

5119
    // group_key function has its own process function
5120
    // do not process there
5121
    if (fmIsGroupKeyFunc(pc->functionId)) {
261,273,254✔
5122
      continue;
×
5123
    }
5124

5125
    if (fmIsSelectValueFunc(pc->functionId)) {
261,266,402✔
5126
      SFunctParam* pFuncParam = &pc->pExpr->base.pParam[0];
261,282,394✔
5127
      int32_t      srcSlotId = pFuncParam->pCol->slotId;
261,286,814✔
5128

5129
      SColumnInfoData* pCol = taosArrayGet(pSrcBlock->pDataBlock, srcSlotId);
261,281,297✔
5130
      if (NULL == pCol) {
261,284,891✔
5131
        return TSDB_CODE_OUT_OF_RANGE;
×
5132
      }
5133
      if ((nullList[i] = colDataIsNull_s(pCol, rowIndex)) == true) {
522,570,472✔
5134
        offset += pCol->info.bytes;
69,744,263✔
5135
        continue;
69,744,263✔
5136
      }
5137

5138
      char* p = colDataGetData(pCol, rowIndex);
191,530,726✔
5139
      if (IS_VAR_DATA_TYPE(pCol->info.type)) {
191,543,800✔
5140
        int32_t bytes = calcStrBytesByType(pCol->info.type, p);
9,888,761✔
5141
        (void)memcpy(pStart + offset, p, bytes);
9,894,081✔
5142
      } else {
5143
        (void)memcpy(pStart + offset, p, pCol->info.bytes);
181,647,452✔
5144
      }
5145

5146
      offset += pCol->info.bytes;
191,539,410✔
5147
      continue;
191,544,520✔
5148
    }
5149
  }
5150

5151
  *res = buf;
122,556,641✔
5152
  return TSDB_CODE_SUCCESS;
122,581,553✔
5153
}
5154

5155
static int32_t doSaveTupleData(SSerializeDataHandle* pHandle, const void* pBuf, size_t length, SWinKey* key,
206,487,743✔
5156
                               STuplePos* pPos, SFunctionStateStore* pStore) {
5157
  STuplePos p = {0};
206,487,743✔
5158
  if (pHandle->pBuf != NULL) {
206,487,743✔
5159
    SFilePage* pPage = NULL;
206,490,896✔
5160

5161
    if (pHandle->currentPage == -1) {
206,490,896✔
5162
      pPage = getNewBufPage(pHandle->pBuf, &pHandle->currentPage);
5,539,242✔
5163
      if (pPage == NULL) {
5,543,206✔
5164
        return terrno;
×
5165
      }
5166
      pPage->num = sizeof(SFilePage);
5,543,206✔
5167
    } else {
5168
      pPage = getBufPage(pHandle->pBuf, pHandle->currentPage);
200,942,609✔
5169
      if (pPage == NULL) {
200,935,538✔
5170
        return terrno;
×
5171
      }
5172
      if (pPage->num + length > getBufPageSize(pHandle->pBuf)) {
200,935,538✔
5173
        // current page is all used, let's prepare a new buffer page
5174
        releaseBufPage(pHandle->pBuf, pPage);
141,062✔
5175
        pPage = getNewBufPage(pHandle->pBuf, &pHandle->currentPage);
141,062✔
5176
        if (pPage == NULL) {
141,062✔
5177
          return terrno;
×
5178
        }
5179
        pPage->num = sizeof(SFilePage);
141,062✔
5180
      }
5181
    }
5182

5183
    p = (STuplePos){.pageId = pHandle->currentPage, .offset = pPage->num};
206,477,938✔
5184
    (void)memcpy(pPage->data + pPage->num, pBuf, length);
206,480,507✔
5185

5186
    pPage->num += length;
206,477,998✔
5187
    setBufPageDirty(pPage, true);
206,480,209✔
5188
    releaseBufPage(pHandle->pBuf, pPage);
206,475,435✔
5189
  } else {  // other tuple save policy
5190
    if (pStore->streamStateFuncPut(pHandle->pState, key, pBuf, length) >= 0) {
782✔
5191
      p.streamTupleKey = *key;
×
5192
    }
5193
  }
5194

5195
  *pPos = p;
206,470,291✔
5196
  return TSDB_CODE_SUCCESS;
206,470,150✔
5197
}
5198

5199
int32_t saveTupleData(SqlFunctionCtx* pCtx, int32_t rowIndex, const SSDataBlock* pSrcBlock, STuplePos* pPos) {
82,398,825✔
5200
  int32_t code = prepareBuf(pCtx);
82,398,825✔
5201
  if (TSDB_CODE_SUCCESS != code) {
82,400,741✔
5202
    return code;
×
5203
  }
5204

5205
  SWinKey key = {0};
82,400,741✔
5206
  if (pCtx->saveHandle.pBuf == NULL) {
82,401,230✔
5207
    SColumnInfoData* pColInfo = taosArrayGet(pSrcBlock->pDataBlock, pCtx->saveHandle.pState->tsIndex);
×
5208
    if (NULL == pColInfo) {
×
5209
      return TSDB_CODE_OUT_OF_RANGE;
×
5210
    }
5211
    if (pColInfo->info.type != TSDB_DATA_TYPE_TIMESTAMP) {
×
5212
      return TSDB_CODE_FUNC_FUNTION_PARA_TYPE;
×
5213
    }
5214
    key.groupId = pSrcBlock->info.id.groupId;
×
5215
    key.ts = *(int64_t*)colDataGetData(pColInfo, rowIndex);
×
5216
    key.numInGroup = pCtx->pExpr->pExpr->_function.bindExprID;
×
5217
  }
5218

5219
  char* buf = NULL;
82,400,728✔
5220
  code = serializeTupleData(pCtx, pSrcBlock, rowIndex, &pCtx->subsidiaries, pCtx->subsidiaries.buf, &buf);
82,398,235✔
5221
  if (TSDB_CODE_SUCCESS != code) {
82,399,174✔
5222
    return code;
×
5223
  }
5224
  return doSaveTupleData(&pCtx->saveHandle, buf, pCtx->subsidiaries.rowLen, &key, pPos, pCtx->pStore);
82,399,174✔
5225
}
5226

5227
static int32_t doUpdateTupleData(SSerializeDataHandle* pHandle, const void* pBuf, size_t length, STuplePos* pPos,
40,183,756✔
5228
                                 SFunctionStateStore* pStore) {
5229
  if (pHandle->pBuf != NULL) {
40,183,756✔
5230
    SFilePage* pPage = getBufPage(pHandle->pBuf, pPos->pageId);
40,185,910✔
5231
    if (pPage == NULL) {
40,184,164✔
5232
      return terrno;
×
5233
    }
5234
    (void)memcpy(pPage->data + pPos->offset, pBuf, length);
40,184,164✔
5235
    setBufPageDirty(pPage, true);
40,183,446✔
5236
    releaseBufPage(pHandle->pBuf, pPage);
40,186,021✔
5237
  } else {
5238
    int32_t code = pStore->streamStateFuncPut(pHandle->pState, &pPos->streamTupleKey, pBuf, length);
×
5239
    if (TSDB_CODE_SUCCESS != code) {
×
5240
      return code;
×
5241
    }
5242
  }
5243

5244
  return TSDB_CODE_SUCCESS;
40,183,391✔
5245
}
5246

5247
int32_t updateTupleData(SqlFunctionCtx* pCtx, int32_t rowIndex, const SSDataBlock* pSrcBlock, STuplePos* pPos) {
40,183,736✔
5248
  int32_t code = prepareBuf(pCtx);
40,183,736✔
5249
  if (TSDB_CODE_SUCCESS != code) {
40,184,945✔
5250
    return code;
×
5251
  }
5252

5253
  char* buf = NULL;
40,184,945✔
5254
  code = serializeTupleData(pCtx, pSrcBlock, rowIndex, &pCtx->subsidiaries, pCtx->subsidiaries.buf, &buf);
40,186,381✔
5255
  if (TSDB_CODE_SUCCESS != code) {
40,185,910✔
5256
    return code;
×
5257
  }
5258
  return doUpdateTupleData(&pCtx->saveHandle, buf, pCtx->subsidiaries.rowLen, pPos, pCtx->pStore);
40,185,910✔
5259
}
5260

5261
static int32_t doLoadTupleData(SSerializeDataHandle* pHandle, const STuplePos* pPos, SFunctionStateStore* pStore,
81,290,236✔
5262
                               char** value) {
5263
  if (pHandle->pBuf != NULL) {
81,290,236✔
5264
    SFilePage* pPage = getBufPage(pHandle->pBuf, pPos->pageId);
81,291,292✔
5265
    if (pPage == NULL) {
81,290,219✔
5266
      *value = NULL;
×
5267
      return terrno;
×
5268
    }
5269
    *value = pPage->data + pPos->offset;
81,290,219✔
5270
    releaseBufPage(pHandle->pBuf, pPage);
81,289,745✔
5271
    return TSDB_CODE_SUCCESS;
81,291,292✔
5272
  } else {
5273
    *value = NULL;
×
5274
    int32_t vLen;
×
5275
    int32_t code = pStore->streamStateFuncGet(pHandle->pState, &pPos->streamTupleKey, (void**)(value), &vLen);
×
5276
    if (TSDB_CODE_SUCCESS != code) {
×
5277
      return code;
×
5278
    }
5279
    return TSDB_CODE_SUCCESS;
×
5280
  }
5281
}
5282

5283
int32_t loadTupleData(SqlFunctionCtx* pCtx, const STuplePos* pPos, char** value) {
81,290,236✔
5284
  return doLoadTupleData(&pCtx->saveHandle, pPos, pCtx->pStore, value);
81,290,236✔
5285
}
5286

5287
int32_t topBotFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
8,460,430✔
5288
  int32_t code = TSDB_CODE_SUCCESS;
8,460,430✔
5289

5290
  SResultRowEntryInfo* pEntryInfo = GET_RES_INFO(pCtx);
8,460,430✔
5291
  STopBotRes*          pRes = getTopBotOutputInfo(pCtx);
8,460,430✔
5292

5293
  int16_t type = pCtx->pExpr->base.resSchema.type;
8,459,742✔
5294
  int32_t slotId = pCtx->pExpr->base.resSchema.slotId;
8,459,742✔
5295

5296
  SColumnInfoData* pCol = taosArrayGet(pBlock->pDataBlock, slotId);
8,460,430✔
5297
  if (NULL == pCol) {
8,459,742✔
5298
    return TSDB_CODE_OUT_OF_RANGE;
×
5299
  }
5300

5301
  // todo assign the tag value and the corresponding row data
5302
  int32_t currentRow = pBlock->info.rows;
8,459,742✔
5303
  if (pEntryInfo->numOfRes <= 0) {
8,460,430✔
5304
    colDataSetNULL(pCol, currentRow);
53,907✔
5305
    code = setSelectivityValue(pCtx, pBlock, &pRes->nullTuplePos, currentRow);
53,907✔
5306
    return code;
53,907✔
5307
  }
5308
  for (int32_t i = 0; i < pEntryInfo->numOfRes; ++i) {
57,439,757✔
5309
    STopBotResItem* pItem = &pRes->pItems[i];
49,033,234✔
5310
    code = colDataSetVal(pCol, currentRow, (const char*)&pItem->v.i, false);
49,032,546✔
5311
    if (TSDB_CODE_SUCCESS != code) {
49,033,922✔
5312
      return code;
×
5313
    }
5314
#ifdef BUF_PAGE_DEBUG
5315
    qDebug("page_finalize i:%d,item:%p,pageId:%d, offset:%d\n", i, pItem, pItem->tuplePos.pageId,
5316
           pItem->tuplePos.offset);
5317
#endif
5318
    code = setSelectivityValue(pCtx, pBlock, &pRes->pItems[i].tuplePos, currentRow);
49,033,922✔
5319
    if (TSDB_CODE_SUCCESS != code) {
49,033,234✔
5320
      return code;
×
5321
    }
5322
    currentRow += 1;
49,033,234✔
5323
  }
5324

5325
  return code;
8,406,523✔
5326
}
5327

5328
int32_t addResult(SqlFunctionCtx* pCtx, STopBotResItem* pSourceItem, int16_t type, bool isTopQuery) {
×
5329
  SResultRowEntryInfo* pEntryInfo = GET_RES_INFO(pCtx);
×
5330
  STopBotRes*          pRes = getTopBotOutputInfo(pCtx);
×
5331
  STopBotResItem*      pItems = pRes->pItems;
×
5332
  int32_t              code = TSDB_CODE_SUCCESS;
×
5333

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

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

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

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

5401
int32_t getSpreadInfoSize() { return (int32_t)sizeof(SSpreadInfo); }
9,215,788✔
5402

5403
bool getSpreadFuncEnv(SFunctionNode* UNUSED_PARAM(pFunc), SFuncExecEnv* pEnv) {
4,161,707✔
5404
  pEnv->calcMemSize = sizeof(SSpreadInfo);
4,161,707✔
5405
  return true;
4,164,021✔
5406
}
5407

5408
int32_t spreadFunctionSetup(SqlFunctionCtx* pCtx, SResultRowEntryInfo* pResultInfo) {
163,628,835✔
5409
  if (pResultInfo->initialized) {
163,628,835✔
5410
    return TSDB_CODE_SUCCESS;
×
5411
  }
5412
  if (TSDB_CODE_SUCCESS != functionSetup(pCtx, pResultInfo)) {
163,631,219✔
5413
    return TSDB_CODE_FUNC_SETUP_ERROR;
×
5414
  }
5415

5416
  SSpreadInfo* pInfo = GET_ROWCELL_INTERBUF(pResultInfo);
163,629,237✔
5417
  SET_DOUBLE_VAL(&pInfo->min, DBL_MAX);
163,629,993✔
5418
  SET_DOUBLE_VAL(&pInfo->max, -DBL_MAX);
163,631,815✔
5419
  pInfo->hasResult = false;
163,629,410✔
5420
  return TSDB_CODE_SUCCESS;
163,626,987✔
5421
}
5422

5423
int32_t spreadFunction(SqlFunctionCtx* pCtx) {
218,475,909✔
5424
  int32_t numOfElems = 0;
218,475,909✔
5425

5426
  // Only the pre-computing information loaded and actual data does not loaded
5427
  SInputColumnInfoData* pInput = &pCtx->input;
218,475,909✔
5428
  SColumnDataAgg*       pAgg = pInput->pColumnDataAgg[0];
218,485,567✔
5429
  int32_t               type = pInput->pData[0]->info.type;
218,502,486✔
5430

5431
  SSpreadInfo* pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
218,520,232✔
5432

5433
  if (pInput->colDataSMAIsSet) {
218,510,025✔
5434
    numOfElems = pInput->numOfRows - pAgg->numOfNull;
50,492,726✔
5435
    if (numOfElems == 0) {
50,494,768✔
5436
      goto _spread_over;
35,821,695✔
5437
    }
5438
    double tmin = 0.0, tmax = 0.0;
14,673,073✔
5439
    if (IS_SIGNED_NUMERIC_TYPE(type) || IS_TIMESTAMP_TYPE(type)) {
14,673,073✔
5440
      tmin = (double)GET_INT64_VAL(&pAgg->min);
7,507,500✔
5441
      tmax = (double)GET_INT64_VAL(&pAgg->max);
7,507,500✔
5442
    } else if (IS_FLOAT_TYPE(type)) {
7,165,573✔
5443
      tmin = GET_DOUBLE_VAL(&pAgg->min);
677✔
5444
      tmax = GET_DOUBLE_VAL(&pAgg->max);
×
5445
    } else if (IS_UNSIGNED_NUMERIC_TYPE(type)) {
7,164,896✔
5446
      tmin = (double)GET_UINT64_VAL(&pAgg->min);
7,164,896✔
5447
      tmax = (double)GET_UINT64_VAL(&pAgg->max);
7,165,573✔
5448
    }
5449

5450
    if (GET_DOUBLE_VAL(&pInfo->min) > tmin) {
14,673,073✔
5451
      SET_DOUBLE_VAL(&pInfo->min, tmin);
667,678✔
5452
    }
5453

5454
    if (GET_DOUBLE_VAL(&pInfo->max) < tmax) {
14,671,708✔
5455
      SET_DOUBLE_VAL(&pInfo->max, tmax);
705,755✔
5456
    }
5457

5458
  } else {  // computing based on the true data block
5459
    SColumnInfoData* pCol = pInput->pData[0];
168,015,067✔
5460

5461
    int32_t start = pInput->startRowIndex;
168,015,577✔
5462
    // check the valid data one by one
5463
    for (int32_t i = start; i < pInput->numOfRows + start; ++i) {
1,249,524,254✔
5464
      if (colDataIsNull_f(pCol, i)) {
1,081,500,241✔
5465
        continue;
290,962,686✔
5466
      }
5467

5468
      char* data = colDataGetData(pCol, i);
790,555,233✔
5469

5470
      double v = 0;
790,557,516✔
5471
      GET_TYPED_DATA(v, double, type, data, typeGetTypeModFromColInfo(&pCol->info));
790,557,516✔
5472
      if (v < GET_DOUBLE_VAL(&pInfo->min)) {
790,555,817✔
5473
        SET_DOUBLE_VAL(&pInfo->min, v);
121,538,471✔
5474
      }
5475

5476
      if (v > GET_DOUBLE_VAL(&pInfo->max)) {
790,539,308✔
5477
        SET_DOUBLE_VAL(&pInfo->max, v);
134,871,291✔
5478
      }
5479

5480
      numOfElems += 1;
790,549,029✔
5481
    }
5482
  }
5483

5484
_spread_over:
168,000,544✔
5485
  // data in the check operation are all null, not output
5486
  SET_VAL(GET_RES_INFO(pCtx), numOfElems, 1);
218,494,624✔
5487
  if (numOfElems > 0) {
218,506,611✔
5488
    pInfo->hasResult = true;
128,507,385✔
5489
  }
5490

5491
  return TSDB_CODE_SUCCESS;
218,493,627✔
5492
}
5493

5494
static void spreadTransferInfo(SSpreadInfo* pInput, SSpreadInfo* pOutput) {
8,415,509✔
5495
  pOutput->hasResult = pInput->hasResult;
8,415,509✔
5496
  if (pInput->max > pOutput->max) {
8,415,509✔
5497
    pOutput->max = pInput->max;
5,885,093✔
5498
  }
5499

5500
  if (pInput->min < pOutput->min) {
8,415,509✔
5501
    pOutput->min = pInput->min;
5,883,740✔
5502
  }
5503
}
8,415,509✔
5504

5505
int32_t spreadFunctionMerge(SqlFunctionCtx* pCtx) {
6,239,299✔
5506
  SInputColumnInfoData* pInput = &pCtx->input;
6,239,299✔
5507
  SColumnInfoData*      pCol = pInput->pData[0];
6,239,299✔
5508

5509
  if (IS_NULL_TYPE(pCol->info.type)) {
6,239,299✔
5510
    SET_VAL(GET_RES_INFO(pCtx), 0, 1);
×
5511
    return TSDB_CODE_SUCCESS;
×
5512
  }
5513

5514
  if (pCol->info.type != TSDB_DATA_TYPE_BINARY) {
6,239,299✔
5515
    return TSDB_CODE_FUNC_FUNTION_PARA_TYPE;
×
5516
  }
5517

5518
  SSpreadInfo* pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
6,239,299✔
5519

5520
  int32_t start = pInput->startRowIndex;
6,239,299✔
5521
  for (int32_t i = start; i < start + pInput->numOfRows; ++i) {
14,948,791✔
5522
    if (colDataIsNull_s(pCol, i)) continue;
17,418,984✔
5523
    char*        data = colDataGetData(pCol, i);
8,709,492✔
5524
    SSpreadInfo* pInputInfo = (SSpreadInfo*)varDataVal(data);
8,709,492✔
5525
    if (pInputInfo->hasResult) {
8,709,492✔
5526
      spreadTransferInfo(pInputInfo, pInfo);
8,415,509✔
5527
    }
5528
  }
5529

5530
  if (pInfo->hasResult) {
6,239,299✔
5531
    GET_RES_INFO(pCtx)->numOfRes = 1;
6,079,928✔
5532
  }
5533

5534
  return TSDB_CODE_SUCCESS;
6,239,299✔
5535
}
5536

5537
int32_t spreadFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
146,357,793✔
5538
  SSpreadInfo* pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
146,357,793✔
5539
  if (pInfo->hasResult == true) {
146,358,389✔
5540
    SET_DOUBLE_VAL(&pInfo->result, pInfo->max - pInfo->min);
92,769,591✔
5541
  } else {
5542
    GET_RES_INFO(pCtx)->isNullRes = 1;
53,587,606✔
5543
  }
5544
  return functionFinalize(pCtx, pBlock);
146,357,793✔
5545
}
5546

5547
int32_t spreadPartialFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
8,724,406✔
5548
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
8,724,406✔
5549
  SSpreadInfo*         pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
8,724,406✔
5550
  int32_t              resultBytes = getSpreadInfoSize();
8,724,406✔
5551
  char*                res = taosMemoryCalloc(resultBytes + VARSTR_HEADER_SIZE, sizeof(char));
8,724,406✔
5552

5553
  if (NULL == res) {
8,724,406✔
5554
    return terrno;
×
5555
  }
5556
  (void)memcpy(varDataVal(res), pInfo, resultBytes);
8,724,406✔
5557
  varDataSetLen(res, resultBytes);
8,724,406✔
5558

5559
  int32_t          slotId = pCtx->pExpr->base.resSchema.slotId;
8,723,802✔
5560
  int32_t          code = TSDB_CODE_SUCCESS;
8,723,802✔
5561
  SColumnInfoData* pCol = taosArrayGet(pBlock->pDataBlock, slotId);
8,723,802✔
5562
  if (NULL == pCol) {
8,723,802✔
5563
    code = terrno;
×
5564
    goto _exit;
×
5565
  }
5566

5567
  code = colDataSetVal(pCol, pBlock->info.rows, res, false);
8,723,802✔
5568
  if (TSDB_CODE_SUCCESS != code) {
8,724,406✔
5569
    goto _exit;
×
5570
  }
5571

5572
_exit:
8,724,406✔
5573
  taosMemoryFree(res);
8,724,406✔
5574
  return code;
8,724,406✔
5575
}
5576

5577
int32_t spreadCombine(SqlFunctionCtx* pDestCtx, SqlFunctionCtx* pSourceCtx) {
×
5578
  SResultRowEntryInfo* pDResInfo = GET_RES_INFO(pDestCtx);
×
5579
  SSpreadInfo*         pDBuf = GET_ROWCELL_INTERBUF(pDResInfo);
×
5580

5581
  SResultRowEntryInfo* pSResInfo = GET_RES_INFO(pSourceCtx);
×
5582
  SSpreadInfo*         pSBuf = GET_ROWCELL_INTERBUF(pSResInfo);
×
5583
  spreadTransferInfo(pSBuf, pDBuf);
×
5584
  pDResInfo->numOfRes = TMAX(pDResInfo->numOfRes, pSResInfo->numOfRes);
×
5585
  pDResInfo->isNullRes &= pSResInfo->isNullRes;
×
5586
  return TSDB_CODE_SUCCESS;
×
5587
}
5588

5589
int32_t getElapsedInfoSize() { return (int32_t)sizeof(SElapsedInfo); }
×
5590

5591
bool getElapsedFuncEnv(SFunctionNode* UNUSED_PARAM(pFunc), SFuncExecEnv* pEnv) {
2,665,448✔
5592
  pEnv->calcMemSize = sizeof(SElapsedInfo);
2,665,448✔
5593
  return true;
2,666,044✔
5594
}
5595

5596
int32_t elapsedFunctionSetup(SqlFunctionCtx* pCtx, SResultRowEntryInfo* pResultInfo) {
5,152,667✔
5597
  if (pResultInfo->initialized) {
5,152,667✔
5598
    return TSDB_CODE_SUCCESS;
×
5599
  }
5600
  if (TSDB_CODE_SUCCESS != functionSetup(pCtx, pResultInfo)) {
5,152,667✔
5601
    return TSDB_CODE_FUNC_SETUP_ERROR;
×
5602
  }
5603

5604
  SElapsedInfo* pInfo = GET_ROWCELL_INTERBUF(pResultInfo);
5,153,263✔
5605
  pInfo->result = 0;
5,153,776✔
5606
  pInfo->min = TSKEY_MAX;
5,153,776✔
5607
  pInfo->max = 0;
5,152,667✔
5608

5609
  if (pCtx->numOfParams > 1) {
5,153,263✔
5610
    pInfo->timeUnit = pCtx->param[1].param.i;
3,410,307✔
5611
  } else {
5612
    pInfo->timeUnit = 1;
1,742,360✔
5613
  }
5614

5615
  return TSDB_CODE_SUCCESS;
5,153,180✔
5616
}
5617

5618
int32_t elapsedFunction(SqlFunctionCtx* pCtx) {
5,217,275✔
5619
  int32_t numOfElems = 0;
5,217,275✔
5620

5621
  // Only the pre-computing information loaded and actual data does not loaded
5622
  SInputColumnInfoData* pInput = &pCtx->input;
5,217,275✔
5623
  SColumnDataAgg*       pAgg = pInput->pColumnDataAgg[0];
5,217,871✔
5624

5625
  SElapsedInfo* pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
5,217,275✔
5626

5627
  numOfElems = pInput->numOfRows;  // since this is the primary timestamp, no need to exclude NULL values
5,218,298✔
5628
  if (numOfElems == 0) {
5,217,871✔
5629
    // for stream
5630
    if (pCtx->end.key != INT64_MIN) {
×
5631
      pInfo->max = pCtx->end.key + 1;
×
5632
    }
5633
    goto _elapsed_over;
×
5634
  }
5635

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

5661
    SColumnInfoData* pCol = pInput->pData[0];
5,217,702✔
5662

5663
    int32_t start = pInput->startRowIndex;
5,217,788✔
5664
    TSKEY*  ptsList = (int64_t*)colDataGetData(pCol, 0);
5,217,275✔
5665
    if (pCtx->order == TSDB_ORDER_DESC) {
5,217,702✔
5666
      if (pCtx->start.key == INT64_MIN) {
38,222✔
5667
        pInfo->max = (pInfo->max < ptsList[start]) ? ptsList[start] : pInfo->max;
38,222✔
5668
      } else {
5669
        pInfo->max = pCtx->start.key + 1;
×
5670
      }
5671

5672
      if (pCtx->end.key == INT64_MIN) {
38,222✔
5673
        pInfo->min =
38,222✔
5674
            (pInfo->min > ptsList[start + pInput->numOfRows - 1]) ? ptsList[start + pInput->numOfRows - 1] : pInfo->min;
38,222✔
5675
      } else {
5676
        pInfo->min = pCtx->end.key;
×
5677
      }
5678
    } else {
5679
      if (pCtx->start.key == INT64_MIN) {
5,180,076✔
5680
        pInfo->min = (pInfo->min > ptsList[start]) ? ptsList[start] : pInfo->min;
5,180,589✔
5681
      } else {
5682
        pInfo->min = pCtx->start.key;
×
5683
      }
5684

5685
      if (pCtx->end.key == INT64_MIN) {
5,180,589✔
5686
        pInfo->max =
5,112,214✔
5687
            (pInfo->max < ptsList[start + pInput->numOfRows - 1]) ? ptsList[start + pInput->numOfRows - 1] : pInfo->max;
5,112,810✔
5688
      } else {
5689
        pInfo->max = pCtx->end.key + 1;
67,266✔
5690
      }
5691
    }
5692
  }
5693

5694
_elapsed_over:
5,217,275✔
5695
  // data in the check operation are all null, not output
5696
  SET_VAL(GET_RES_INFO(pCtx), numOfElems, 1);
5,217,275✔
5697

5698
  return TSDB_CODE_SUCCESS;
5,218,811✔
5699
}
5700

5701
static void elapsedTransferInfo(SElapsedInfo* pInput, SElapsedInfo* pOutput) {
×
5702
  pOutput->timeUnit = pInput->timeUnit;
×
5703
  if (pOutput->min > pInput->min) {
×
5704
    pOutput->min = pInput->min;
×
5705
  }
5706

5707
  if (pOutput->max < pInput->max) {
×
5708
    pOutput->max = pInput->max;
×
5709
  }
5710
}
×
5711

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

5719
  SElapsedInfo* pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
×
5720

5721
  int32_t start = pInput->startRowIndex;
×
5722

5723
  for (int32_t i = start; i < start + pInput->numOfRows; ++i) {
×
5724
    char*         data = colDataGetData(pCol, i);
×
5725
    SElapsedInfo* pInputInfo = (SElapsedInfo*)varDataVal(data);
×
5726
    elapsedTransferInfo(pInputInfo, pInfo);
×
5727
  }
5728

5729
  SET_VAL(GET_RES_INFO(pCtx), 1, 1);
×
5730
  return TSDB_CODE_SUCCESS;
×
5731
}
5732

5733
int32_t elapsedFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
5,153,180✔
5734
  SElapsedInfo* pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
5,153,180✔
5735
  double        result = (double)(pInfo->max - pInfo->min);
5,153,776✔
5736
  pInfo->result = fabs(result) / pInfo->timeUnit;
5,153,180✔
5737
  return functionFinalize(pCtx, pBlock);
5,153,776✔
5738
}
5739

5740
int32_t elapsedPartialFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
×
5741
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
×
5742
  SElapsedInfo*        pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
×
5743
  int32_t              resultBytes = getElapsedInfoSize();
×
5744
  char*                res = taosMemoryCalloc(resultBytes + VARSTR_HEADER_SIZE, sizeof(char));
×
5745

5746
  if (NULL == res) {
×
5747
    return terrno;
×
5748
  }
5749
  (void)memcpy(varDataVal(res), pInfo, resultBytes);
×
5750
  varDataSetLen(res, resultBytes);
×
5751

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

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

5769
int32_t elapsedCombine(SqlFunctionCtx* pDestCtx, SqlFunctionCtx* pSourceCtx) {
×
5770
  SResultRowEntryInfo* pDResInfo = GET_RES_INFO(pDestCtx);
×
5771
  SElapsedInfo*        pDBuf = GET_ROWCELL_INTERBUF(pDResInfo);
×
5772

5773
  SResultRowEntryInfo* pSResInfo = GET_RES_INFO(pSourceCtx);
×
5774
  SElapsedInfo*        pSBuf = GET_ROWCELL_INTERBUF(pSResInfo);
×
5775

5776
  elapsedTransferInfo(pSBuf, pDBuf);
×
5777
  pDResInfo->numOfRes = TMAX(pDResInfo->numOfRes, pSResInfo->numOfRes);
×
5778
  pDResInfo->isNullRes &= pSResInfo->isNullRes;
×
5779
  return TSDB_CODE_SUCCESS;
×
5780
}
5781

5782
int32_t getHistogramInfoSize() {
833,223✔
5783
  return (int32_t)sizeof(SHistoFuncInfo) + HISTOGRAM_MAX_BINS_NUM * sizeof(SHistoFuncBin);
833,223✔
5784
}
5785

5786
bool getHistogramFuncEnv(SFunctionNode* UNUSED_PARAM(pFunc), SFuncExecEnv* pEnv) {
1,502,065✔
5787
  pEnv->calcMemSize = sizeof(SHistoFuncInfo) + HISTOGRAM_MAX_BINS_NUM * sizeof(SHistoFuncBin);
1,502,065✔
5788
  return true;
1,503,661✔
5789
}
5790

5791
static int8_t getHistogramBinType(char* binTypeStr) {
1,031,043✔
5792
  int8_t binType;
5793
  if (strcasecmp(binTypeStr, "user_input") == 0) {
1,031,043✔
5794
    binType = USER_INPUT_BIN;
420,321✔
5795
  } else if (strcasecmp(binTypeStr, "linear_bin") == 0) {
610,722✔
5796
    binType = LINEAR_BIN;
479,378✔
5797
  } else if (strcasecmp(binTypeStr, "log_bin") == 0) {
131,344✔
5798
    binType = LOG_BIN;
131,940✔
5799
  } else {
5800
    binType = UNKNOWN_BIN;
×
5801
  }
5802

5803
  return binType;
1,031,043✔
5804
}
5805

5806
static int32_t getHistogramBinDesc(SHistoFuncInfo* pInfo, char* binDescStr, int8_t binType, bool normalized) {
1,030,807✔
5807
  cJSON*  binDesc = cJSON_Parse(binDescStr);
1,030,807✔
5808
  int32_t numOfBins;
5809
  double* intervals;
5810
  if (cJSON_IsObject(binDesc)) { /* linaer/log bins */
1,032,235✔
5811
    int32_t numOfParams = cJSON_GetArraySize(binDesc);
611,318✔
5812
    int32_t startIndex;
5813
    if (numOfParams != 4) {
610,722✔
5814
      cJSON_Delete(binDesc);
×
5815
      return TSDB_CODE_FAILED;
×
5816
    }
5817

5818
    cJSON* start = cJSON_GetObjectItem(binDesc, "start");
610,722✔
5819
    cJSON* factor = cJSON_GetObjectItem(binDesc, "factor");
611,914✔
5820
    cJSON* width = cJSON_GetObjectItem(binDesc, "width");
611,914✔
5821
    cJSON* count = cJSON_GetObjectItem(binDesc, "count");
611,914✔
5822
    cJSON* infinity = cJSON_GetObjectItem(binDesc, "infinity");
610,722✔
5823

5824
    if (!cJSON_IsNumber(start) || !cJSON_IsNumber(count) || !cJSON_IsBool(infinity)) {
611,914✔
5825
      cJSON_Delete(binDesc);
×
5826
      return TSDB_CODE_FAILED;
×
5827
    }
5828

5829
    if (count->valueint <= 0 || count->valueint > 1000) {  // limit count to 1000
611,318✔
5830
      cJSON_Delete(binDesc);
596✔
5831
      return TSDB_CODE_FAILED;
×
5832
    }
5833

5834
    if (isinf(start->valuedouble) || (width != NULL && isinf(width->valuedouble)) ||
611,318✔
5835
        (factor != NULL && isinf(factor->valuedouble)) || (count != NULL && isinf(count->valuedouble))) {
611,318✔
5836
      cJSON_Delete(binDesc);
×
5837
      return TSDB_CODE_FAILED;
×
5838
    }
5839

5840
    int32_t counter = (int32_t)count->valueint;
611,914✔
5841
    if (infinity->valueint == false) {
611,914✔
5842
      startIndex = 0;
171,648✔
5843
      numOfBins = counter + 1;
171,648✔
5844
    } else {
5845
      startIndex = 1;
440,266✔
5846
      numOfBins = counter + 3;
440,266✔
5847
    }
5848

5849
    intervals = taosMemoryCalloc(numOfBins, sizeof(double));
611,914✔
5850
    if (NULL == intervals) {
610,722✔
5851
      cJSON_Delete(binDesc);
×
5852
      qError("histogram function out of memory");
×
5853
      return terrno;
×
5854
    }
5855
    if (cJSON_IsNumber(width) && factor == NULL && binType == LINEAR_BIN) {
610,722✔
5856
      // linear bin process
5857
      if (width->valuedouble == 0) {
478,782✔
5858
        taosMemoryFree(intervals);
×
5859
        cJSON_Delete(binDesc);
×
5860
        return TSDB_CODE_FAILED;
×
5861
      }
5862
      for (int i = 0; i < counter + 1; ++i) {
3,010,622✔
5863
        intervals[startIndex] = start->valuedouble + i * width->valuedouble;
2,533,568✔
5864
        if (isinf(intervals[startIndex])) {
2,533,592✔
5865
          taosMemoryFree(intervals);
×
5866
          cJSON_Delete(binDesc);
×
5867
          return TSDB_CODE_FAILED;
×
5868
        }
5869
        startIndex++;
2,531,840✔
5870
      }
5871
    } else if (cJSON_IsNumber(factor) && width == NULL && binType == LOG_BIN) {
131,940✔
5872
      // log bin process
5873
      if (start->valuedouble == 0) {
131,940✔
5874
        taosMemoryFree(intervals);
×
5875
        cJSON_Delete(binDesc);
×
5876
        return TSDB_CODE_FAILED;
×
5877
      }
5878
      if (factor->valuedouble < 0 || factor->valuedouble == 0 || factor->valuedouble == 1) {
131,940✔
5879
        taosMemoryFree(intervals);
×
5880
        cJSON_Delete(binDesc);
×
5881
        return TSDB_CODE_FAILED;
×
5882
      }
5883
      for (int i = 0; i < counter + 1; ++i) {
580,284✔
5884
        intervals[startIndex] = start->valuedouble * pow(factor->valuedouble, i * 1.0);
448,344✔
5885
        if (isinf(intervals[startIndex])) {
448,344✔
5886
          taosMemoryFree(intervals);
×
5887
          cJSON_Delete(binDesc);
×
5888
          return TSDB_CODE_FAILED;
×
5889
        }
5890
        startIndex++;
448,344✔
5891
      }
5892
    } else {
5893
      taosMemoryFree(intervals);
×
5894
      cJSON_Delete(binDesc);
×
5895
      return TSDB_CODE_FAILED;
×
5896
    }
5897

5898
    if (infinity->valueint == true) {
608,994✔
5899
      intervals[0] = -INFINITY;
440,266✔
5900
      intervals[numOfBins - 1] = INFINITY;
440,266✔
5901
      // in case of desc bin orders, -inf/inf should be swapped
5902
      if (numOfBins < 4) {
440,266✔
5903
        return TSDB_CODE_FAILED;
×
5904
      }
5905
      if (intervals[1] > intervals[numOfBins - 2]) {
440,266✔
5906
        TSWAP(intervals[0], intervals[numOfBins - 1]);
46,116✔
5907
      }
5908
    }
5909
  } else if (cJSON_IsArray(binDesc)) { /* user input bins */
420,321✔
5910
    if (binType != USER_INPUT_BIN) {
420,321✔
5911
      cJSON_Delete(binDesc);
×
5912
      return TSDB_CODE_FAILED;
×
5913
    }
5914
    numOfBins = cJSON_GetArraySize(binDesc);
420,321✔
5915
    intervals = taosMemoryCalloc(numOfBins, sizeof(double));
419,725✔
5916
    if (NULL == intervals) {
419,489✔
5917
      cJSON_Delete(binDesc);
×
5918
      qError("histogram function out of memory");
×
5919
      return terrno;
×
5920
    }
5921
    cJSON* bin = binDesc->child;
419,489✔
5922
    if (bin == NULL) {
418,893✔
5923
      taosMemoryFree(intervals);
×
5924
      cJSON_Delete(binDesc);
×
5925
      return TSDB_CODE_FAILED;
×
5926
    }
5927
    int i = 0;
418,893✔
5928
    while (bin) {
1,753,617✔
5929
      intervals[i] = bin->valuedouble;
1,333,892✔
5930
      if (!cJSON_IsNumber(bin)) {
1,335,140✔
5931
        taosMemoryFree(intervals);
×
5932
        cJSON_Delete(binDesc);
×
5933
        return TSDB_CODE_FAILED;
×
5934
      }
5935
      if (i != 0 && intervals[i] <= intervals[i - 1]) {
1,334,128✔
5936
        taosMemoryFree(intervals);
×
5937
        cJSON_Delete(binDesc);
×
5938
        return TSDB_CODE_FAILED;
×
5939
      }
5940
      bin = bin->next;
1,335,140✔
5941
      i++;
1,334,724✔
5942
    }
5943
  } else {
5944
    cJSON_Delete(binDesc);
×
5945
    return TSDB_CODE_FAILED;
×
5946
  }
5947

5948
  pInfo->numOfBins = numOfBins - 1;
1,031,043✔
5949
  pInfo->normalized = normalized;
1,030,627✔
5950
  for (int32_t i = 0; i < pInfo->numOfBins; ++i) {
5,197,440✔
5951
    pInfo->bins[i].lower = intervals[i] < intervals[i + 1] ? intervals[i] : intervals[i + 1];
4,167,645✔
5952
    pInfo->bins[i].upper = intervals[i + 1] > intervals[i] ? intervals[i + 1] : intervals[i];
4,167,049✔
5953
    pInfo->bins[i].count = 0;
4,166,205✔
5954
  }
5955

5956
  taosMemoryFree(intervals);
1,030,211✔
5957
  cJSON_Delete(binDesc);
1,031,043✔
5958

5959
  return TSDB_CODE_SUCCESS;
1,030,211✔
5960
}
5961

5962
int32_t histogramFunctionSetup(SqlFunctionCtx* pCtx, SResultRowEntryInfo* pResultInfo) {
1,031,639✔
5963
  if (pResultInfo->initialized) {
1,031,639✔
5964
    return TSDB_CODE_SUCCESS;
×
5965
  }
5966
  if (TSDB_CODE_SUCCESS != functionSetup(pCtx, pResultInfo)) {
1,032,235✔
5967
    return TSDB_CODE_FUNC_SETUP_ERROR;
×
5968
  }
5969

5970
  SHistoFuncInfo* pInfo = GET_ROWCELL_INTERBUF(pResultInfo);
1,032,235✔
5971
  pInfo->numOfBins = 0;
1,032,235✔
5972
  pInfo->totalCount = 0;
1,032,235✔
5973
  pInfo->normalized = 0;
1,031,639✔
5974

5975
  char* binTypeStr = taosStrndup(varDataVal(pCtx->param[1].param.pz), varDataLen(pCtx->param[1].param.pz));
1,032,235✔
5976
  if (binTypeStr == NULL) {
1,031,043✔
5977
    return terrno;
×
5978
  }
5979
  int8_t binType = getHistogramBinType(binTypeStr);
1,031,043✔
5980
  taosMemoryFree(binTypeStr);
1,031,639✔
5981

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

6001
  return TSDB_CODE_SUCCESS;
1,030,807✔
6002
}
6003

6004
static int32_t histogramFunctionImpl(SqlFunctionCtx* pCtx, bool isPartial) {
1,201,365✔
6005
  SHistoFuncInfo* pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
1,201,365✔
6006

6007
  SInputColumnInfoData* pInput = &pCtx->input;
1,201,197✔
6008
  SColumnInfoData*      pCol = pInput->pData[0];
1,201,781✔
6009

6010
  int32_t type = pInput->pData[0]->info.type;
1,200,342✔
6011

6012
  int32_t start = pInput->startRowIndex;
1,202,793✔
6013
  int32_t numOfRows = pInput->numOfRows;
1,203,221✔
6014

6015
  int32_t numOfElems = 0;
1,213,452✔
6016
  for (int32_t i = start; i < numOfRows + start; ++i) {
173,867,410✔
6017
    if (pCol->hasNull && colDataIsNull_f(pCol, i)) {
172,663,605✔
6018
      continue;
111,822,448✔
6019
    }
6020

6021
    numOfElems++;
60,835,062✔
6022

6023
    char*  data = colDataGetData(pCol, i);
60,835,062✔
6024
    double v;
6025
    GET_TYPED_DATA(v, double, type, data, typeGetTypeModFromColInfo(&pCol->info));
60,867,711✔
6026

6027
    for (int32_t k = 0; k < pInfo->numOfBins; ++k) {
188,683,432✔
6028
      if (v > pInfo->bins[k].lower && v <= pInfo->bins[k].upper) {
184,312,944✔
6029
        pInfo->bins[k].count++;
56,496,186✔
6030
        pInfo->totalCount++;
56,494,398✔
6031
        break;
56,494,994✔
6032
      }
6033
    }
6034
  }
6035

6036
  if (!isPartial) {
1,203,805✔
6037
    GET_RES_INFO(pCtx)->numOfRes = pInfo->numOfBins;
816,099✔
6038
  } else {
6039
    GET_RES_INFO(pCtx)->numOfRes = 1;
387,706✔
6040
  }
6041
  return TSDB_CODE_SUCCESS;
1,202,793✔
6042
}
6043

6044
int32_t histogramFunction(SqlFunctionCtx* pCtx) { return histogramFunctionImpl(pCtx, false); }
814,075✔
6045

6046
int32_t histogramFunctionPartial(SqlFunctionCtx* pCtx) { return histogramFunctionImpl(pCtx, true); }
387,706✔
6047

6048
static void histogramTransferInfo(SHistoFuncInfo* pInput, SHistoFuncInfo* pOutput) {
247,226✔
6049
  pOutput->normalized = pInput->normalized;
247,226✔
6050
  pOutput->numOfBins = pInput->numOfBins;
247,226✔
6051
  pOutput->totalCount += pInput->totalCount;
247,226✔
6052
  for (int32_t k = 0; k < pOutput->numOfBins; ++k) {
1,633,488✔
6053
    pOutput->bins[k].lower = pInput->bins[k].lower;
1,386,262✔
6054
    pOutput->bins[k].upper = pInput->bins[k].upper;
1,386,262✔
6055
    pOutput->bins[k].count += pInput->bins[k].count;
1,386,262✔
6056
  }
6057
}
247,226✔
6058

6059
int32_t histogramFunctionMerge(SqlFunctionCtx* pCtx) {
247,226✔
6060
  SInputColumnInfoData* pInput = &pCtx->input;
247,226✔
6061
  SColumnInfoData*      pCol = pInput->pData[0];
247,226✔
6062
  if (pCol->info.type != TSDB_DATA_TYPE_BINARY) {
247,226✔
6063
    return TSDB_CODE_FUNC_FUNTION_PARA_TYPE;
×
6064
  }
6065

6066
  SHistoFuncInfo* pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
247,226✔
6067

6068
  int32_t start = pInput->startRowIndex;
247,226✔
6069

6070
  for (int32_t i = start; i < start + pInput->numOfRows; ++i) {
494,452✔
6071
    char*           data = colDataGetData(pCol, i);
247,226✔
6072
    SHistoFuncInfo* pInputInfo = (SHistoFuncInfo*)varDataVal(data);
247,226✔
6073
    histogramTransferInfo(pInputInfo, pInfo);
247,226✔
6074
  }
6075

6076
  SET_VAL(GET_RES_INFO(pCtx), pInfo->numOfBins, pInfo->numOfBins);
247,226✔
6077
  return TSDB_CODE_SUCCESS;
247,226✔
6078
}
6079

6080
int32_t histogramFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
1,007,458✔
6081
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
1,007,458✔
6082
  SHistoFuncInfo*      pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
1,007,874✔
6083
  int32_t              slotId = pCtx->pExpr->base.resSchema.slotId;
1,007,458✔
6084
  SColumnInfoData*     pCol = taosArrayGet(pBlock->pDataBlock, slotId);
1,007,458✔
6085
  int32_t              code = TSDB_CODE_SUCCESS;
1,007,458✔
6086

6087
  int32_t currentRow = pBlock->info.rows;
1,007,458✔
6088
  if (NULL == pCol) {
1,007,458✔
6089
    return TSDB_CODE_OUT_OF_RANGE;
×
6090
  }
6091

6092
  if (pInfo->normalized) {
1,007,458✔
6093
    for (int32_t k = 0; k < pResInfo->numOfRes; ++k) {
4,167,580✔
6094
      if (pInfo->totalCount != 0) {
3,330,335✔
6095
        pInfo->bins[k].percentage = pInfo->bins[k].count / (double)pInfo->totalCount;
1,221,343✔
6096
      } else {
6097
        pInfo->bins[k].percentage = 0;
2,108,992✔
6098
      }
6099
    }
6100
  }
6101

6102
  for (int32_t i = 0; i < pResInfo->numOfRes; ++i) {
5,014,808✔
6103
    int32_t len;
6104
    char    buf[512] = {0};
4,005,922✔
6105
    if (!pInfo->normalized) {
4,005,922✔
6106
      len = snprintf(varDataVal(buf), sizeof(buf) - VARSTR_HEADER_SIZE,
675,587✔
6107
                     "{\"lower_bin\":%g, \"upper_bin\":%g, \"count\":%" PRId64 "}", pInfo->bins[i].lower,
6108
                     pInfo->bins[i].upper, pInfo->bins[i].count);
6109
    } else {
6110
      len = snprintf(varDataVal(buf), sizeof(buf) - VARSTR_HEADER_SIZE,
3,330,335✔
6111
                     "{\"lower_bin\":%g, \"upper_bin\":%g, \"count\":%lf}", pInfo->bins[i].lower, pInfo->bins[i].upper,
6112
                     pInfo->bins[i].percentage);
6113
    }
6114
    varDataSetLen(buf, len);
4,006,102✔
6115
    code = colDataSetVal(pCol, currentRow, buf, false);
4,006,518✔
6116
    if (TSDB_CODE_SUCCESS != code) {
4,006,518✔
6117
      return code;
×
6118
    }
6119
    currentRow++;
4,006,518✔
6120
  }
6121

6122
  return code;
1,008,470✔
6123
}
6124

6125
int32_t histogramPartialFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
247,226✔
6126
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
247,226✔
6127
  SHistoFuncInfo*      pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
247,226✔
6128
  int32_t              resultBytes = getHistogramInfoSize();
247,226✔
6129
  char*                res = taosMemoryCalloc(resultBytes + VARSTR_HEADER_SIZE, sizeof(char));
247,226✔
6130

6131
  if (NULL == res) {
247,226✔
6132
    return terrno;
×
6133
  }
6134
  (void)memcpy(varDataVal(res), pInfo, resultBytes);
247,226✔
6135
  varDataSetLen(res, resultBytes);
247,226✔
6136

6137
  int32_t          slotId = pCtx->pExpr->base.resSchema.slotId;
247,226✔
6138
  int32_t          code = TSDB_CODE_SUCCESS;
247,226✔
6139
  SColumnInfoData* pCol = taosArrayGet(pBlock->pDataBlock, slotId);
247,226✔
6140
  if (NULL == pCol) {
247,226✔
6141
    code = terrno;
×
6142
    goto _exit;
×
6143
  }
6144
  code = colDataSetVal(pCol, pBlock->info.rows, res, false);
247,226✔
6145

6146
_exit:
247,226✔
6147
  taosMemoryFree(res);
247,226✔
6148
  return code;
247,226✔
6149
}
6150

6151
int32_t histogramCombine(SqlFunctionCtx* pDestCtx, SqlFunctionCtx* pSourceCtx) {
×
6152
  SResultRowEntryInfo* pDResInfo = GET_RES_INFO(pDestCtx);
×
6153
  SHistoFuncInfo*      pDBuf = GET_ROWCELL_INTERBUF(pDResInfo);
×
6154

6155
  SResultRowEntryInfo* pSResInfo = GET_RES_INFO(pSourceCtx);
×
6156
  SHistoFuncInfo*      pSBuf = GET_ROWCELL_INTERBUF(pSResInfo);
×
6157

6158
  histogramTransferInfo(pSBuf, pDBuf);
×
6159
  pDResInfo->numOfRes = TMAX(pDResInfo->numOfRes, pSResInfo->numOfRes);
×
6160
  pDResInfo->isNullRes &= pSResInfo->isNullRes;
×
6161
  return TSDB_CODE_SUCCESS;
×
6162
}
6163

6164
int32_t getHLLInfoSize() { return (int32_t)sizeof(SHLLInfo); }
296,464✔
6165

6166
bool getHLLFuncEnv(SFunctionNode* UNUSED_PARAM(pFunc), SFuncExecEnv* pEnv) {
4,267,250✔
6167
  pEnv->calcMemSize = sizeof(SHLLInfo);
4,267,250✔
6168
  return true;
4,267,250✔
6169
}
6170

6171
static uint8_t hllCountNum(void* data, int32_t bytes, int32_t* buk) {
676,568,464✔
6172
  uint64_t hash = MurmurHash3_64(data, bytes);
676,568,464✔
6173
  int32_t  index = hash & HLL_BUCKET_MASK;
676,546,683✔
6174
  hash >>= HLL_BUCKET_BITS;
676,546,683✔
6175
  hash |= ((uint64_t)1 << HLL_DATA_BITS);
676,546,683✔
6176
  uint64_t bit = 1;
676,546,683✔
6177
  uint8_t  count = 1;
676,546,683✔
6178
  while ((hash & bit) == 0) {
1,159,502,270✔
6179
    count++;
482,955,587✔
6180
    bit <<= 1;
482,955,587✔
6181
  }
6182
  *buk = index;
676,546,683✔
6183
  return count;
676,541,384✔
6184
}
6185

6186
static void hllBucketHisto(uint8_t* buckets, int32_t* bucketHisto) {
10,171,606✔
6187
  uint64_t* word = (uint64_t*)buckets;
10,171,606✔
6188
  uint8_t*  bytes;
6189

6190
  for (int32_t j = 0; j < HLL_BUCKETS >> 3; j++) {
2,147,483,647✔
6191
    if (*word == 0) {
2,147,483,647✔
6192
      bucketHisto[0] += 8;
2,147,483,647✔
6193
    } else {
6194
      bytes = (uint8_t*)word;
40,812,781✔
6195
      bucketHisto[bytes[0]]++;
40,812,781✔
6196
      bucketHisto[bytes[1]]++;
44,873,389✔
6197
      bucketHisto[bytes[2]]++;
44,873,389✔
6198
      bucketHisto[bytes[3]]++;
44,873,389✔
6199
      bucketHisto[bytes[4]]++;
44,873,389✔
6200
      bucketHisto[bytes[5]]++;
44,873,389✔
6201
      bucketHisto[bytes[6]]++;
44,872,793✔
6202
      bucketHisto[bytes[7]]++;
44,873,389✔
6203
    }
6204
    word++;
2,147,483,647✔
6205
  }
6206
}
7,991,242✔
6207
static double hllTau(double x) {
10,171,606✔
6208
  if (x == 0. || x == 1.) return 0.;
10,171,606✔
6209
  double zPrime;
6210
  double y = 1.0;
×
6211
  double z = 1 - x;
×
6212
  do {
6213
    x = sqrt(x);
×
6214
    zPrime = z;
×
6215
    y *= 0.5;
×
6216
    z -= pow(1 - x, 2) * y;
×
6217
  } while (zPrime != z);
×
6218
  return z / 3;
×
6219
}
6220

6221
static double hllSigma(double x) {
10,171,606✔
6222
  if (x == 1.0) return INFINITY;
10,171,606✔
6223
  double zPrime;
6224
  double y = 1;
7,372,061✔
6225
  double z = x;
7,372,061✔
6226
  do {
6227
    x *= x;
145,526,740✔
6228
    zPrime = z;
145,526,740✔
6229
    z += x * y;
145,526,740✔
6230
    y += y;
145,526,740✔
6231
  } while (zPrime != z);
145,526,740✔
6232
  return z;
7,372,061✔
6233
}
6234

6235
// estimate the cardinality, the algorithm refer this paper: "New cardinality estimation algorithms for HyperLogLog
6236
// sketches"
6237
static uint64_t hllCountCnt(uint8_t* buckets) {
10,171,606✔
6238
  double  m = HLL_BUCKETS;
10,171,606✔
6239
  int32_t buckethisto[64] = {0};
10,171,606✔
6240
  hllBucketHisto(buckets, buckethisto);
10,171,606✔
6241

6242
  double z = m * hllTau((m - buckethisto[HLL_DATA_BITS + 1]) / (double)m);
10,171,606✔
6243
  for (int j = HLL_DATA_BITS; j >= 1; --j) {
518,683,962✔
6244
    z += buckethisto[j];
508,512,356✔
6245
    z *= 0.5;
508,512,356✔
6246
  }
6247

6248
  z += m * hllSigma(buckethisto[0] / (double)m);
10,171,606✔
6249
  double E = (double)llroundl(HLL_ALPHA_INF * m * m / z);
10,171,010✔
6250

6251
  return (uint64_t)E;
10,171,010✔
6252
}
6253

6254
int32_t hllFunction(SqlFunctionCtx* pCtx) {
10,449,124✔
6255
  SHLLInfo* pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
10,449,124✔
6256

6257
  SInputColumnInfoData* pInput = &pCtx->input;
10,452,118✔
6258
  SColumnInfoData*      pCol = pInput->pData[0];
10,452,714✔
6259

6260
  int32_t type = pCol->info.type;
10,450,330✔
6261
  int32_t bytes = pCol->info.bytes;
10,452,700✔
6262

6263
  int32_t start = pInput->startRowIndex;
10,452,700✔
6264
  int32_t numOfRows = pInput->numOfRows;
10,450,330✔
6265

6266
  int32_t numOfElems = 0;
10,451,508✔
6267
  if (IS_NULL_TYPE(type)) {
10,451,508✔
6268
    goto _hll_over;
159,771✔
6269
  }
6270

6271
  for (int32_t i = start; i < numOfRows + start; ++i) {
798,671,017✔
6272
    if (pCol->hasNull && colDataIsNull_s(pCol, i)) {
905,516,508✔
6273
      continue;
111,877,560✔
6274
    }
6275

6276
    numOfElems++;
676,484,100✔
6277

6278
    char* data = colDataGetData(pCol, i);
676,484,100✔
6279
    if (IS_VAR_DATA_TYPE(type)) {
676,567,272✔
6280
      if (IS_STR_DATA_BLOB(type)) {
84,703,480✔
6281
        bytes = blobDataLen(data);
×
6282
        data = blobDataVal(data);
×
6283
      } else {
6284
        bytes = varDataLen(data);
84,707,652✔
6285
        data = varDataVal(data);
84,707,056✔
6286
      }
6287
    }
6288

6289
    int32_t index = 0;
676,573,828✔
6290
    uint8_t count = hllCountNum(data, bytes, &index);
676,569,656✔
6291
    uint8_t oldcount = pInfo->buckets[index];
676,543,833✔
6292
    if (count > oldcount) {
676,544,429✔
6293
      pInfo->buckets[index] = count;
89,409,835✔
6294
    }
6295
  }
6296

6297
_hll_over:
10,292,725✔
6298
  pInfo->totalCount += numOfElems;
10,452,496✔
6299

6300
  if (pInfo->totalCount == 0 && !tsCountAlwaysReturnValue) {
10,454,488✔
6301
    SET_VAL(GET_RES_INFO(pCtx), 0, 1);
792✔
6302
  } else {
6303
    SET_VAL(GET_RES_INFO(pCtx), 1, 1);
10,452,504✔
6304
  }
6305

6306
  return TSDB_CODE_SUCCESS;
10,453,892✔
6307
}
6308

6309
static void hllTransferInfo(SHLLInfo* pInput, SHLLInfo* pOutput) {
296,464✔
6310
  for (int32_t k = 0; k < HLL_BUCKETS; ++k) {
2,147,483,647✔
6311
    if (pOutput->buckets[k] < pInput->buckets[k]) {
2,147,483,647✔
6312
      pOutput->buckets[k] = pInput->buckets[k];
31,056,834✔
6313
    }
6314
  }
6315
  pOutput->totalCount += pInput->totalCount;
312✔
6316
}
296,464✔
6317

6318
int32_t hllFunctionMerge(SqlFunctionCtx* pCtx) {
294,684✔
6319
  SInputColumnInfoData* pInput = &pCtx->input;
294,684✔
6320
  SColumnInfoData*      pCol = pInput->pData[0];
294,684✔
6321

6322
  if (IS_NULL_TYPE(pCol->info.type)) {
294,684✔
6323
    SET_VAL(GET_RES_INFO(pCtx), 0, 1);
×
6324
    return TSDB_CODE_SUCCESS;
×
6325
  }
6326

6327
  if (pCol->info.type != TSDB_DATA_TYPE_BINARY) {
294,684✔
6328
    return TSDB_CODE_SUCCESS;
×
6329
  }
6330

6331
  SHLLInfo* pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
294,684✔
6332

6333
  int32_t start = pInput->startRowIndex;
294,684✔
6334

6335
  for (int32_t i = start; i < start + pInput->numOfRows; ++i) {
591,148✔
6336
    if (colDataIsNull_s(pCol, i)) continue;
592,928✔
6337
    char*     data = colDataGetData(pCol, i);
296,464✔
6338
    SHLLInfo* pInputInfo = (SHLLInfo*)varDataVal(data);
296,464✔
6339
    hllTransferInfo(pInputInfo, pInfo);
296,464✔
6340
  }
6341

6342
  if (pInfo->totalCount == 0 && !tsCountAlwaysReturnValue) {
294,684✔
6343
    SET_VAL(GET_RES_INFO(pCtx), 0, 1);
88✔
6344
  } else {
6345
    SET_VAL(GET_RES_INFO(pCtx), 1, 1);
294,596✔
6346
  }
6347

6348
  return TSDB_CODE_SUCCESS;
294,684✔
6349
}
6350

6351
int32_t hllFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
10,171,606✔
6352
  SResultRowEntryInfo* pInfo = GET_RES_INFO(pCtx);
10,171,606✔
6353

6354
  SHLLInfo* pHllInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
10,171,606✔
6355
  pHllInfo->result = hllCountCnt(pHllInfo->buckets);
10,171,606✔
6356
  if (tsCountAlwaysReturnValue && pHllInfo->result == 0) {
10,171,010✔
6357
    pInfo->numOfRes = 1;
2,799,369✔
6358
  }
6359

6360
  return functionFinalize(pCtx, pBlock);
10,171,010✔
6361
}
6362

6363
int32_t hllPartialFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
296,464✔
6364
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
296,464✔
6365
  SHLLInfo*            pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
296,464✔
6366
  int32_t              resultBytes = getHLLInfoSize();
296,464✔
6367
  char*                res = taosMemoryCalloc(resultBytes + VARSTR_HEADER_SIZE, sizeof(char));
296,464✔
6368

6369
  if (NULL == res) {
296,464✔
6370
    return terrno;
×
6371
  }
6372
  (void)memcpy(varDataVal(res), pInfo, resultBytes);
296,464✔
6373
  varDataSetLen(res, resultBytes);
296,464✔
6374

6375
  int32_t          slotId = pCtx->pExpr->base.resSchema.slotId;
296,464✔
6376
  int32_t          code = TSDB_CODE_SUCCESS;
296,464✔
6377
  SColumnInfoData* pCol = taosArrayGet(pBlock->pDataBlock, slotId);
296,464✔
6378
  if (NULL == pCol) {
296,464✔
6379
    code = terrno;
×
6380
    goto _exit;
×
6381
  }
6382

6383
  code = colDataSetVal(pCol, pBlock->info.rows, res, false);
296,464✔
6384

6385
_exit:
296,464✔
6386
  taosMemoryFree(res);
296,464✔
6387
  return code;
296,464✔
6388
}
6389

6390
int32_t hllCombine(SqlFunctionCtx* pDestCtx, SqlFunctionCtx* pSourceCtx) {
×
6391
  SResultRowEntryInfo* pDResInfo = GET_RES_INFO(pDestCtx);
×
6392
  SHLLInfo*            pDBuf = GET_ROWCELL_INTERBUF(pDResInfo);
×
6393

6394
  SResultRowEntryInfo* pSResInfo = GET_RES_INFO(pSourceCtx);
×
6395
  SHLLInfo*            pSBuf = GET_ROWCELL_INTERBUF(pSResInfo);
×
6396

6397
  hllTransferInfo(pSBuf, pDBuf);
×
6398
  pDResInfo->numOfRes = TMAX(pDResInfo->numOfRes, pSResInfo->numOfRes);
×
6399
  pDResInfo->isNullRes &= pSResInfo->isNullRes;
×
6400
  return TSDB_CODE_SUCCESS;
×
6401
}
6402

6403
bool getStateFuncEnv(SFunctionNode* UNUSED_PARAM(pFunc), SFuncExecEnv* pEnv) {
1,515,199✔
6404
  pEnv->calcMemSize = sizeof(SStateInfo);
1,515,199✔
6405
  return true;
1,514,783✔
6406
}
6407

6408
static int8_t getStateOpType(char* opStr) {
1,807,506✔
6409
  int8_t opType;
6410
  if (strncasecmp(opStr, "LT", 2) == 0) {
1,807,506✔
6411
    opType = STATE_OPER_LT;
455,866✔
6412
  } else if (strncasecmp(opStr, "GT", 2) == 0) {
1,351,640✔
6413
    opType = STATE_OPER_GT;
326,072✔
6414
  } else if (strncasecmp(opStr, "LE", 2) == 0) {
1,025,568✔
6415
    opType = STATE_OPER_LE;
200,732✔
6416
  } else if (strncasecmp(opStr, "GE", 2) == 0) {
824,836✔
6417
    opType = STATE_OPER_GE;
307,800✔
6418
  } else if (strncasecmp(opStr, "NE", 2) == 0) {
517,036✔
6419
    opType = STATE_OPER_NE;
395,012✔
6420
  } else if (strncasecmp(opStr, "EQ", 2) == 0) {
122,024✔
6421
    opType = STATE_OPER_EQ;
122,024✔
6422
  } else {
6423
    opType = STATE_OPER_INVALID;
×
6424
  }
6425

6426
  return opType;
1,807,506✔
6427
}
6428

6429
static bool checkStateOp(int8_t op, SColumnInfoData* pCol, int32_t index, SVariant param) {
183,788,014✔
6430
  char* data = colDataGetData(pCol, index);
183,788,014✔
6431
  switch (pCol->info.type) {
183,788,014✔
6432
    case TSDB_DATA_TYPE_TINYINT: {
24,259,712✔
6433
      int8_t v = *(int8_t*)data;
24,259,712✔
6434
      STATE_COMP(op, v, param);
24,259,712✔
6435
      break;
×
6436
    }
6437
    case TSDB_DATA_TYPE_UTINYINT: {
33,537,248✔
6438
      uint8_t v = *(uint8_t*)data;
33,537,248✔
6439
      STATE_COMP(op, v, param);
33,537,248✔
6440
      break;
×
6441
    }
6442
    case TSDB_DATA_TYPE_SMALLINT: {
762,664✔
6443
      int16_t v = *(int16_t*)data;
762,664✔
6444
      STATE_COMP(op, v, param);
762,664✔
6445
      break;
×
6446
    }
6447
    case TSDB_DATA_TYPE_USMALLINT: {
695,520✔
6448
      uint16_t v = *(uint16_t*)data;
695,520✔
6449
      STATE_COMP(op, v, param);
695,520✔
6450
      break;
×
6451
    }
6452
    case TSDB_DATA_TYPE_INT: {
101,062,881✔
6453
      int32_t v = *(int32_t*)data;
101,062,881✔
6454
      STATE_COMP(op, v, param);
101,062,881✔
6455
      break;
×
6456
    }
6457
    case TSDB_DATA_TYPE_UINT: {
695,520✔
6458
      uint32_t v = *(uint32_t*)data;
695,520✔
6459
      STATE_COMP(op, v, param);
695,520✔
6460
      break;
×
6461
    }
6462
    case TSDB_DATA_TYPE_BIGINT: {
1,374,044✔
6463
      int64_t v = *(int64_t*)data;
1,374,044✔
6464
      STATE_COMP(op, v, param);
1,374,044✔
6465
      break;
×
6466
    }
6467
    case TSDB_DATA_TYPE_UBIGINT: {
695,520✔
6468
      uint64_t v = *(uint64_t*)data;
695,520✔
6469
      STATE_COMP(op, v, param);
695,520✔
6470
      break;
×
6471
    }
6472
    case TSDB_DATA_TYPE_FLOAT: {
19,634,064✔
6473
      float v = *(float*)data;
19,634,064✔
6474
      STATE_COMP(op, v, param);
19,634,064✔
6475
      break;
×
6476
    }
6477
    case TSDB_DATA_TYPE_DOUBLE: {
1,070,841✔
6478
      double v = *(double*)data;
1,070,841✔
6479
      STATE_COMP(op, v, param);
1,070,841✔
6480
      break;
×
6481
    }
6482
    default: {
×
6483
      return false;
×
6484
    }
6485
  }
6486
  return false;
×
6487
}
6488

6489
int32_t stateCountFunction(SqlFunctionCtx* pCtx) {
475,890✔
6490
  int32_t              code = TSDB_CODE_SUCCESS;
475,890✔
6491
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
475,890✔
6492
  SStateInfo*          pInfo = GET_ROWCELL_INTERBUF(pResInfo);
475,890✔
6493

6494
  SInputColumnInfoData* pInput = &pCtx->input;
475,890✔
6495
  TSKEY*                tsList = (int64_t*)pInput->pPTS->pData;
475,890✔
6496

6497
  SColumnInfoData* pInputCol = pInput->pData[0];
475,890✔
6498

6499
  int32_t          numOfElems = 0;
475,890✔
6500
  SColumnInfoData* pOutput = (SColumnInfoData*)pCtx->pOutput;
475,890✔
6501

6502
  int8_t op = getStateOpType(varDataVal(pCtx->param[1].param.pz));
475,890✔
6503
  if (STATE_OPER_INVALID == op) {
475,890✔
6504
    return 0;
×
6505
  }
6506

6507
  for (int32_t i = pInput->startRowIndex; i < pInput->numOfRows + pInput->startRowIndex; i += 1) {
111,659,604✔
6508
    if (pInfo->isPrevTsSet == true && tsList[i] == pInfo->prevTs) {
111,185,602✔
6509
      return TSDB_CODE_FUNC_DUP_TIMESTAMP;
1,888✔
6510
    } else {
6511
      pInfo->prevTs = tsList[i];
111,183,714✔
6512
    }
6513

6514
    pInfo->isPrevTsSet = true;
111,183,714✔
6515
    numOfElems++;
111,183,714✔
6516

6517
    if (colDataIsNull_f(pInputCol, i)) {
111,183,714✔
6518
      colDataSetNULL(pOutput, i);
20,591,650✔
6519
      // handle selectivity
6520
      if (pCtx->subsidiaries.num > 0) {
20,591,650✔
6521
        code = appendSelectivityValue(pCtx, i, pCtx->offset + numOfElems - 1);
4,401✔
6522
        if (TSDB_CODE_SUCCESS != code) {
4,401✔
6523
          return code;
×
6524
        }
6525
      }
6526
      continue;
20,591,650✔
6527
    }
6528

6529
    bool ret = checkStateOp(op, pInputCol, i, pCtx->param[2].param);
90,592,064✔
6530

6531
    int64_t output = -1;
90,592,064✔
6532
    if (ret) {
90,592,064✔
6533
      output = ++pInfo->count;
38,765,149✔
6534
    } else {
6535
      pInfo->count = 0;
51,826,915✔
6536
    }
6537
    code = colDataSetVal(pOutput, pCtx->offset + numOfElems - 1, (char*)&output, false);
90,592,064✔
6538
    if (TSDB_CODE_SUCCESS != code) {
90,592,064✔
6539
      return code;
×
6540
    }
6541

6542
    // handle selectivity
6543
    if (pCtx->subsidiaries.num > 0) {
90,592,064✔
6544
      code = appendSelectivityValue(pCtx, i, pCtx->offset + numOfElems - 1);
937,108✔
6545
      if (TSDB_CODE_SUCCESS != code) {
937,108✔
6546
        return code;
×
6547
      }
6548
    }
6549
  }
6550

6551
  pResInfo->numOfRes = numOfElems;
474,002✔
6552
  return TSDB_CODE_SUCCESS;
474,002✔
6553
}
6554

6555
int32_t stateDurationFunction(SqlFunctionCtx* pCtx) {
1,331,616✔
6556
  int32_t              code = TSDB_CODE_SUCCESS;
1,331,616✔
6557
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
1,331,616✔
6558
  SStateInfo*          pInfo = GET_ROWCELL_INTERBUF(pResInfo);
1,331,616✔
6559

6560
  SInputColumnInfoData* pInput = &pCtx->input;
1,331,616✔
6561
  TSKEY*                tsList = (int64_t*)pInput->pPTS->pData;
1,331,616✔
6562

6563
  SColumnInfoData* pInputCol = pInput->pData[0];
1,331,616✔
6564

6565
  int32_t          numOfElems = 0;
1,331,616✔
6566
  SColumnInfoData* pOutput = (SColumnInfoData*)pCtx->pOutput;
1,331,616✔
6567

6568
  // TODO: process timeUnit for different db precisions
6569
  int32_t timeUnit = 1;
1,331,616✔
6570
  if (pCtx->numOfParams == 5) {  // TODO: param number incorrect
1,331,616✔
6571
    timeUnit = pCtx->param[3].param.i;
1,055,712✔
6572
  }
6573

6574
  int8_t op = getStateOpType(varDataVal(pCtx->param[1].param.pz));
1,331,616✔
6575
  if (STATE_OPER_INVALID == op) {
1,331,616✔
6576
    return TSDB_CODE_INVALID_PARA;
×
6577
  }
6578

6579
  for (int32_t i = pInput->startRowIndex; i < pInput->numOfRows + pInput->startRowIndex; i += 1) {
152,106,720✔
6580
    if (pInfo->isPrevTsSet == true && tsList[i] == pInfo->prevTs) {
150,829,824✔
6581
      return TSDB_CODE_FUNC_DUP_TIMESTAMP;
1,888✔
6582
    } else {
6583
      pInfo->prevTs = tsList[i];
150,810,880✔
6584
    }
6585

6586
    pInfo->isPrevTsSet = true;
150,822,528✔
6587
    numOfElems++;
150,822,528✔
6588

6589
    if (colDataIsNull_f(pInputCol, i)) {
150,822,528✔
6590
      colDataSetNULL(pOutput, i);
57,628,242✔
6591
      // handle selectivity
6592
      if (pCtx->subsidiaries.num > 0) {
57,644,466✔
6593
        code = appendSelectivityValue(pCtx, i, pCtx->offset + numOfElems - 1);
8,549✔
6594
        if (TSDB_CODE_SUCCESS != code) {
8,549✔
6595
          return code;
×
6596
        }
6597
      }
6598
      continue;
57,644,466✔
6599
    }
6600

6601
    bool    ret = checkStateOp(op, pInputCol, i, pCtx->param[2].param);
93,195,950✔
6602
    int64_t output = -1;
93,195,950✔
6603
    if (ret) {
93,195,950✔
6604
      if (pInfo->durationStart == 0) {
57,524,276✔
6605
        output = 0;
2,329,999✔
6606
        pInfo->durationStart = tsList[i];
2,329,999✔
6607
      } else {
6608
        output = (tsList[i] - pInfo->durationStart) / timeUnit;
55,194,277✔
6609
      }
6610
    } else {
6611
      pInfo->durationStart = 0;
35,671,674✔
6612
    }
6613
    code = colDataSetVal(pOutput, pCtx->offset + numOfElems - 1, (char*)&output, false);
93,195,950✔
6614
    if (TSDB_CODE_SUCCESS != code) {
93,195,950✔
6615
      return code;
×
6616
    }
6617

6618
    // handle selectivity
6619
    if (pCtx->subsidiaries.num > 0) {
93,195,950✔
6620
      code = appendSelectivityValue(pCtx, i, pCtx->offset + numOfElems - 1);
106,132✔
6621
      if (TSDB_CODE_SUCCESS != code) {
106,132✔
6622
        return code;
×
6623
      }
6624
    }
6625
  }
6626

6627
  pResInfo->numOfRes = numOfElems;
1,329,728✔
6628
  return TSDB_CODE_SUCCESS;
1,329,728✔
6629
}
6630

6631
bool getCsumFuncEnv(SFunctionNode* UNUSED_PARAM(pFunc), SFuncExecEnv* pEnv) {
786,252✔
6632
  pEnv->calcMemSize = sizeof(SSumRes);
786,252✔
6633
  return true;
786,252✔
6634
}
6635

6636
int32_t csumFunction(SqlFunctionCtx* pCtx) {
1,179,453✔
6637
  int32_t              code = TSDB_CODE_SUCCESS;
1,179,453✔
6638
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
1,179,453✔
6639
  SSumRes*             pSumRes = GET_ROWCELL_INTERBUF(pResInfo);
1,179,453✔
6640

6641
  SInputColumnInfoData* pInput = &pCtx->input;
1,179,453✔
6642
  TSKEY*                tsList = (int64_t*)pInput->pPTS->pData;
1,179,453✔
6643

6644
  SColumnInfoData* pInputCol = pInput->pData[0];
1,179,453✔
6645
  SColumnInfoData* pOutput = (SColumnInfoData*)pCtx->pOutput;
1,179,453✔
6646

6647
  int32_t numOfElems = 0;
1,179,453✔
6648
  int32_t type = pInputCol->info.type;
1,179,453✔
6649
  int32_t startOffset = pCtx->offset;
1,179,453✔
6650
  for (int32_t i = pInput->startRowIndex; i < pInput->numOfRows + pInput->startRowIndex; i += 1) {
216,052,780✔
6651
    if (pSumRes->isPrevTsSet == true && tsList[i] == pSumRes->prevTs) {
214,841,663✔
6652
      return TSDB_CODE_FUNC_DUP_TIMESTAMP;
8,520✔
6653
    } else {
6654
      pSumRes->prevTs = tsList[i];
214,833,807✔
6655
    }
6656
    pSumRes->isPrevTsSet = true;
214,834,639✔
6657

6658
    int32_t pos = startOffset + numOfElems;
214,835,055✔
6659
    if (colDataIsNull_f(pInputCol, i)) {
214,835,055✔
6660
      // colDataSetNULL(pOutput, i);
6661
      continue;
88,359,931✔
6662
    }
6663

6664
    char* data = colDataGetData(pInputCol, i);
126,513,396✔
6665
    if (IS_SIGNED_NUMERIC_TYPE(type)) {
230,741,234✔
6666
      int64_t v;
6667
      GET_TYPED_DATA(v, int64_t, type, data, typeGetTypeModFromColInfo(&pInputCol->info));
104,227,838✔
6668
      pSumRes->isum += v;
104,227,838✔
6669
      code = colDataSetVal(pOutput, pos, (char*)&pSumRes->isum, false);
104,227,838✔
6670
      if (TSDB_CODE_SUCCESS != code) {
104,227,838✔
6671
        return code;
×
6672
      }
6673
    } else if (IS_UNSIGNED_NUMERIC_TYPE(type)) {
33,390,868✔
6674
      uint64_t v;
6675
      GET_TYPED_DATA(v, uint64_t, type, data, typeGetTypeModFromColInfo(&pInputCol->info));
11,105,310✔
6676
      pSumRes->usum += v;
11,105,310✔
6677
      code = colDataSetVal(pOutput, pos, (char*)&pSumRes->usum, false);
11,105,310✔
6678
      if (TSDB_CODE_SUCCESS != code) {
11,105,310✔
6679
        return code;
×
6680
      }
6681
    } else if (IS_FLOAT_TYPE(type)) {
11,180,248✔
6682
      double v;
6683
      GET_TYPED_DATA(v, double, type, data, typeGetTypeModFromColInfo(&pInputCol->info));
11,180,248✔
6684
      pSumRes->dsum += v;
11,180,248✔
6685
      // check for overflow
6686
      if (isinf(pSumRes->dsum) || isnan(pSumRes->dsum)) {
11,180,248✔
6687
        colDataSetNULL(pOutput, pos);
982✔
6688
      } else {
6689
        code = colDataSetVal(pOutput, pos, (char*)&pSumRes->dsum, false);
11,179,266✔
6690
        if (TSDB_CODE_SUCCESS != code) {
11,179,266✔
6691
          return code;
×
6692
        }
6693
      }
6694
    }
6695

6696
    // handle selectivity
6697
    if (pCtx->subsidiaries.num > 0) {
126,513,396✔
6698
      code = appendSelectivityValue(pCtx, i, pos);
25,174✔
6699
      if (TSDB_CODE_SUCCESS != code) {
25,174✔
6700
        return code;
×
6701
      }
6702
    }
6703

6704
    numOfElems++;
126,513,396✔
6705
  }
6706

6707
  pResInfo->numOfRes = numOfElems;
1,170,933✔
6708
  return TSDB_CODE_SUCCESS;
1,170,933✔
6709
}
6710

6711
bool getMavgFuncEnv(SFunctionNode* UNUSED_PARAM(pFunc), SFuncExecEnv* pEnv) {
449,377✔
6712
  pEnv->calcMemSize = sizeof(SMavgInfo) + MAVG_MAX_POINTS_NUM * sizeof(double);
449,377✔
6713
  return true;
449,377✔
6714
}
6715

6716
int32_t mavgFunctionSetup(SqlFunctionCtx* pCtx, SResultRowEntryInfo* pResultInfo) {
1,226,585✔
6717
  if (pResultInfo->initialized) {
1,226,585✔
6718
    return TSDB_CODE_SUCCESS;
575,241✔
6719
  }
6720
  if (TSDB_CODE_SUCCESS != functionSetup(pCtx, pResultInfo)) {
651,344✔
6721
    return TSDB_CODE_FUNC_SETUP_ERROR;
×
6722
  }
6723

6724
  SMavgInfo* pInfo = GET_ROWCELL_INTERBUF(pResultInfo);
651,344✔
6725
  pInfo->pos = 0;
651,344✔
6726
  pInfo->sum = 0;
651,344✔
6727
  pInfo->prevTs = -1;
651,344✔
6728
  pInfo->isPrevTsSet = false;
651,344✔
6729
  pInfo->numOfPoints = pCtx->param[1].param.i;
651,344✔
6730
  if (pInfo->numOfPoints < 1 || pInfo->numOfPoints > MAVG_MAX_POINTS_NUM) {
651,344✔
6731
    return TSDB_CODE_FUNC_FUNTION_PARA_VALUE;
×
6732
  }
6733
  pInfo->pointsMeet = false;
651,344✔
6734

6735
  return TSDB_CODE_SUCCESS;
651,344✔
6736
}
6737

6738
int32_t mavgFunction(SqlFunctionCtx* pCtx) {
676,761✔
6739
  int32_t              code = TSDB_CODE_SUCCESS;
676,761✔
6740
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
676,761✔
6741
  SMavgInfo*           pInfo = GET_ROWCELL_INTERBUF(pResInfo);
676,761✔
6742

6743
  SInputColumnInfoData* pInput = &pCtx->input;
676,761✔
6744
  TSKEY*                tsList = (int64_t*)pInput->pPTS->pData;
676,761✔
6745

6746
  SColumnInfoData* pInputCol = pInput->pData[0];
676,761✔
6747
  SColumnInfoData* pTsOutput = pCtx->pTsOutput;
676,761✔
6748
  SColumnInfoData* pOutput = (SColumnInfoData*)pCtx->pOutput;
676,761✔
6749

6750
  int32_t numOfElems = 0;
676,761✔
6751
  int32_t type = pInputCol->info.type;
676,761✔
6752
  int32_t startOffset = pCtx->offset;
676,761✔
6753
  for (int32_t i = pInput->startRowIndex; i < pInput->numOfRows + pInput->startRowIndex; i += 1) {
173,053,811✔
6754
    if (pInfo->isPrevTsSet == true && tsList[i] == pInfo->prevTs) {
172,378,938✔
6755
      return TSDB_CODE_FUNC_DUP_TIMESTAMP;
1,888✔
6756
    } else {
6757
      pInfo->prevTs = tsList[i];
172,377,050✔
6758
    }
6759
    pInfo->isPrevTsSet = true;
172,377,050✔
6760

6761
    int32_t pos = startOffset + numOfElems;
172,377,050✔
6762
    if (colDataIsNull_f(pInputCol, i)) {
172,377,050✔
6763
      // colDataSetNULL(pOutput, i);
6764
      continue;
39,453,201✔
6765
    }
6766

6767
    char*  data = colDataGetData(pInputCol, i);
132,923,849✔
6768
    double v;
6769
    GET_TYPED_DATA(v, double, type, data, typeGetTypeModFromColInfo(&pInputCol->info));
132,923,849✔
6770

6771
    if (!pInfo->pointsMeet && (pInfo->pos < pInfo->numOfPoints - 1)) {
132,923,849✔
6772
      pInfo->points[pInfo->pos] = v;
23,442,095✔
6773
      pInfo->sum += v;
23,442,095✔
6774
    } else {
6775
      if (!pInfo->pointsMeet && (pInfo->pos == pInfo->numOfPoints - 1)) {
109,481,754✔
6776
        pInfo->sum += v;
294,052✔
6777
        pInfo->pointsMeet = true;
294,052✔
6778
      } else {
6779
        pInfo->sum = pInfo->sum + v - pInfo->points[pInfo->pos];
109,187,702✔
6780
      }
6781

6782
      pInfo->points[pInfo->pos] = v;
109,481,754✔
6783
      double result = pInfo->sum / pInfo->numOfPoints;
109,481,754✔
6784
      // check for overflow
6785
      if (isinf(result) || isnan(result)) {
109,481,754✔
6786
        colDataSetNULL(pOutput, pos);
×
6787
      } else {
6788
        code = colDataSetVal(pOutput, pos, (char*)&result, false);
109,481,754✔
6789
        if (TSDB_CODE_SUCCESS != code) {
109,481,754✔
6790
          return code;
×
6791
        }
6792
      }
6793

6794
      // handle selectivity
6795
      if (pCtx->subsidiaries.num > 0) {
109,481,754✔
6796
        code = appendSelectivityValue(pCtx, i, pos);
36,888✔
6797
        if (TSDB_CODE_SUCCESS != code) {
36,888✔
6798
          return code;
×
6799
        }
6800
      }
6801

6802
      numOfElems++;
109,481,754✔
6803
    }
6804

6805
    pInfo->pos++;
132,923,849✔
6806
    if (pInfo->pos == pInfo->numOfPoints) {
132,923,849✔
6807
      pInfo->pos = 0;
18,676,188✔
6808
    }
6809
  }
6810

6811
  pResInfo->numOfRes = numOfElems;
674,873✔
6812
  return TSDB_CODE_SUCCESS;
674,873✔
6813
}
6814

6815
static SSampleInfo* getSampleOutputInfo(SqlFunctionCtx* pCtx) {
4,676,635✔
6816
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
4,676,635✔
6817
  SSampleInfo*         pInfo = GET_ROWCELL_INTERBUF(pResInfo);
4,676,635✔
6818

6819
  pInfo->data = (char*)pInfo + sizeof(SSampleInfo);
4,676,635✔
6820
  pInfo->tuplePos = (STuplePos*)((char*)pInfo + sizeof(SSampleInfo) + pInfo->samples * pInfo->colBytes);
4,676,635✔
6821

6822
  return pInfo;
4,676,635✔
6823
}
6824

6825
bool getSampleFuncEnv(SFunctionNode* pFunc, SFuncExecEnv* pEnv) {
888,490✔
6826
  SColumnNode* pCol = (SColumnNode*)nodesListGetNode(pFunc->pParameterList, 0);
888,490✔
6827
  SValueNode*  pVal = (SValueNode*)nodesListGetNode(pFunc->pParameterList, 1);
888,490✔
6828
  int32_t      numOfSamples = pVal->datum.i;
886,322✔
6829
  pEnv->calcMemSize = sizeof(SSampleInfo) + numOfSamples * (pCol->node.resType.bytes + sizeof(STuplePos));
885,490✔
6830
  return true;
886,906✔
6831
}
6832

6833
int32_t sampleFunctionSetup(SqlFunctionCtx* pCtx, SResultRowEntryInfo* pResultInfo) {
1,943,031✔
6834
  if (pResultInfo->initialized) {
1,943,031✔
6835
    return TSDB_CODE_SUCCESS;
×
6836
  }
6837
  if (TSDB_CODE_SUCCESS != functionSetup(pCtx, pResultInfo)) {
1,943,031✔
6838
    return TSDB_CODE_FUNC_SETUP_ERROR;
×
6839
  }
6840

6841
  taosSeedRand(taosSafeRand());
1,943,031✔
6842

6843
  SSampleInfo* pInfo = GET_ROWCELL_INTERBUF(pResultInfo);
1,943,031✔
6844
  pInfo->samples = pCtx->param[1].param.i;
1,943,031✔
6845
  pInfo->totalPoints = 0;
1,943,031✔
6846
  pInfo->numSampled = 0;
1,943,031✔
6847
  pInfo->colType = pCtx->resDataInfo.type;
1,943,031✔
6848
  pInfo->colBytes = pCtx->resDataInfo.bytes;
1,943,031✔
6849
  pInfo->nullTuplePos.pageId = -1;
1,943,031✔
6850
  pInfo->nullTupleSaved = false;
1,943,031✔
6851
  pInfo->data = (char*)pInfo + sizeof(SSampleInfo);
1,943,031✔
6852
  pInfo->tuplePos = (STuplePos*)((char*)pInfo + sizeof(SSampleInfo) + pInfo->samples * pInfo->colBytes);
1,943,031✔
6853

6854
  return TSDB_CODE_SUCCESS;
1,943,031✔
6855
}
6856

6857
static void sampleAssignResult(SSampleInfo* pInfo, char* data, int32_t index) {
64,782,349✔
6858
  assignVal(pInfo->data + index * pInfo->colBytes, data, pInfo->colBytes, pInfo->colType);
64,782,349✔
6859
}
64,782,349✔
6860

6861
static int32_t doReservoirSample(SqlFunctionCtx* pCtx, SSampleInfo* pInfo, char* data, int32_t index) {
104,303,634✔
6862
  pInfo->totalPoints++;
104,303,634✔
6863
  if (pInfo->numSampled < pInfo->samples) {
104,303,634✔
6864
    sampleAssignResult(pInfo, data, pInfo->numSampled);
63,017,687✔
6865
    if (pCtx->subsidiaries.num > 0) {
63,017,687✔
6866
      int32_t code = saveTupleData(pCtx, index, pCtx->pSrcBlock, &pInfo->tuplePos[pInfo->numSampled]);
1,120,033✔
6867
      if (code != TSDB_CODE_SUCCESS) {
1,120,033✔
6868
        return code;
×
6869
      }
6870
    }
6871
    pInfo->numSampled++;
63,017,687✔
6872
  } else {
6873
    int32_t j = (int32_t)(taosRand() % (uint64_t)pInfo->totalPoints);
41,285,947✔
6874
    if (j < pInfo->samples) {
41,285,947✔
6875
      sampleAssignResult(pInfo, data, j);
1,764,662✔
6876
      if (pCtx->subsidiaries.num > 0) {
1,764,662✔
6877
        int32_t code = updateTupleData(pCtx, index, pCtx->pSrcBlock, &pInfo->tuplePos[j]);
392,416✔
6878
        if (code != TSDB_CODE_SUCCESS) {
392,416✔
6879
          return code;
×
6880
        }
6881
      }
6882
    }
6883
  }
6884

6885
  return TSDB_CODE_SUCCESS;
104,303,634✔
6886
}
6887

6888
int32_t sampleFunction(SqlFunctionCtx* pCtx) {
2,737,879✔
6889
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
2,737,879✔
6890
  SSampleInfo*         pInfo = getSampleOutputInfo(pCtx);
2,737,879✔
6891

6892
  SInputColumnInfoData* pInput = &pCtx->input;
2,737,879✔
6893

6894
  SColumnInfoData* pInputCol = pInput->pData[0];
2,737,879✔
6895
  for (int32_t i = pInput->startRowIndex; i < pInput->numOfRows + pInput->startRowIndex; i += 1) {
170,230,253✔
6896
    if (colDataIsNull_s(pInputCol, i)) {
334,984,748✔
6897
      continue;
63,188,740✔
6898
    }
6899

6900
    char*   data = colDataGetData(pInputCol, i);
104,303,634✔
6901
    int32_t code = doReservoirSample(pCtx, pInfo, data, i);
104,303,634✔
6902
    if (code != TSDB_CODE_SUCCESS) {
104,303,634✔
6903
      return code;
×
6904
    }
6905
  }
6906

6907
  if (pInfo->numSampled == 0 && pCtx->subsidiaries.num > 0 && !pInfo->nullTupleSaved) {
2,737,879✔
6908
    int32_t code = saveTupleData(pCtx, pInput->startRowIndex, pCtx->pSrcBlock, &pInfo->nullTuplePos);
1,948✔
6909
    if (code != TSDB_CODE_SUCCESS) {
1,948✔
6910
      return code;
×
6911
    }
6912
    pInfo->nullTupleSaved = true;
1,948✔
6913
  }
6914

6915
  SET_VAL(pResInfo, pInfo->numSampled, pInfo->numSampled);
2,737,879✔
6916
  return TSDB_CODE_SUCCESS;
2,737,879✔
6917
}
6918

6919
int32_t sampleFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
1,938,756✔
6920
  int32_t              code = TSDB_CODE_SUCCESS;
1,938,756✔
6921
  SResultRowEntryInfo* pEntryInfo = GET_RES_INFO(pCtx);
1,938,756✔
6922

6923
  SSampleInfo* pInfo = getSampleOutputInfo(pCtx);
1,938,756✔
6924
  pEntryInfo->complete = true;
1,938,756✔
6925

6926
  int32_t          slotId = pCtx->pExpr->base.resSchema.slotId;
1,938,756✔
6927
  SColumnInfoData* pCol = taosArrayGet(pBlock->pDataBlock, slotId);
1,938,756✔
6928
  if (NULL == pCol) {
1,938,756✔
6929
    return TSDB_CODE_OUT_OF_RANGE;
×
6930
  }
6931

6932
  int32_t currentRow = pBlock->info.rows;
1,938,756✔
6933
  if (pInfo->numSampled == 0) {
1,938,756✔
6934
    colDataSetNULL(pCol, currentRow);
370,620✔
6935
    code = setSelectivityValue(pCtx, pBlock, &pInfo->nullTuplePos, currentRow);
370,620✔
6936
    return code;
370,620✔
6937
  }
6938
  for (int32_t i = 0; i < pInfo->numSampled; ++i) {
64,585,335✔
6939
    code = colDataSetVal(pCol, currentRow + i, pInfo->data + i * pInfo->colBytes, false);
63,017,687✔
6940
    if (TSDB_CODE_SUCCESS != code) {
63,017,199✔
6941
      return code;
×
6942
    }
6943
    code = setSelectivityValue(pCtx, pBlock, &pInfo->tuplePos[i], currentRow + i);
63,017,199✔
6944
    if (TSDB_CODE_SUCCESS != code) {
63,017,199✔
6945
      return code;
×
6946
    }
6947
  }
6948

6949
  return code;
1,567,648✔
6950
}
6951

6952
bool getTailFuncEnv(SFunctionNode* pFunc, SFuncExecEnv* pEnv) {
×
6953
#if 0
6954
  SColumnNode* pCol = (SColumnNode*)nodesListGetNode(pFunc->pParameterList, 0);
6955
  SValueNode*  pVal = (SValueNode*)nodesListGetNode(pFunc->pParameterList, 1);
6956
  int32_t      numOfPoints = pVal->datum.i;
6957
  pEnv->calcMemSize = sizeof(STailInfo) + numOfPoints * (POINTER_BYTES + sizeof(STailItem) + pCol->node.resType.bytes);
6958
#endif
6959
  return true;
×
6960
}
6961

6962
int32_t tailFunctionSetup(SqlFunctionCtx* pCtx, SResultRowEntryInfo* pResultInfo) {
×
6963
#if 0
6964
  if (!functionSetup(pCtx, pResultInfo)) {
6965
    return false;
6966
  }
6967

6968
  STailInfo* pInfo = GET_ROWCELL_INTERBUF(pResultInfo);
6969
  pInfo->numAdded = 0;
6970
  pInfo->numOfPoints = pCtx->param[1].param.i;
6971
  if (pCtx->numOfParams == 4) {
6972
    pInfo->offset = pCtx->param[2].param.i;
6973
  } else {
6974
    pInfo->offset = 0;
6975
  }
6976
  pInfo->colType = pCtx->resDataInfo.type;
6977
  pInfo->colBytes = pCtx->resDataInfo.bytes;
6978
  if ((pInfo->numOfPoints < 1 || pInfo->numOfPoints > TAIL_MAX_POINTS_NUM) ||
6979
      (pInfo->numOfPoints < 0 || pInfo->numOfPoints > TAIL_MAX_OFFSET)) {
6980
    return false;
6981
  }
6982

6983
  pInfo->pItems = (STailItem**)((char*)pInfo + sizeof(STailInfo));
6984
  char* pItem = (char*)pInfo->pItems + pInfo->numOfPoints * POINTER_BYTES;
6985

6986
  size_t unitSize = sizeof(STailItem) + pInfo->colBytes;
6987
  for (int32_t i = 0; i < pInfo->numOfPoints; ++i) {
6988
    pInfo->pItems[i] = (STailItem*)(pItem + i * unitSize);
6989
    pInfo->pItems[i]->isNull = false;
6990
  }
6991
#endif
6992
  return TSDB_CODE_SUCCESS;
×
6993
}
6994

6995
static void tailAssignResult(STailItem* pItem, char* data, int32_t colBytes, TSKEY ts, bool isNull) {
×
6996
#if 0
6997
  pItem->timestamp = ts;
6998
  if (isNull) {
6999
    pItem->isNull = true;
7000
  } else {
7001
    pItem->isNull = false;
7002
    memcpy(pItem->data, data, colBytes);
7003
  }
7004
#endif
7005
}
×
7006

7007
#if 0
7008
static int32_t tailCompFn(const void* p1, const void* p2, const void* param) {
7009
  STailItem* d1 = *(STailItem**)p1;
7010
  STailItem* d2 = *(STailItem**)p2;
7011
  return compareInt64Val(&d1->timestamp, &d2->timestamp);
7012
}
7013

7014
static void doTailAdd(STailInfo* pInfo, char* data, TSKEY ts, bool isNull) {
7015
  STailItem** pList = pInfo->pItems;
7016
  if (pInfo->numAdded < pInfo->numOfPoints) {
7017
    tailAssignResult(pList[pInfo->numAdded], data, pInfo->colBytes, ts, isNull);
7018
    taosheapsort((void*)pList, sizeof(STailItem**), pInfo->numAdded + 1, NULL, tailCompFn, 0);
7019
    pInfo->numAdded++;
7020
  } else if (pList[0]->timestamp < ts) {
7021
    tailAssignResult(pList[0], data, pInfo->colBytes, ts, isNull);
7022
    taosheapadjust((void*)pList, sizeof(STailItem**), 0, pInfo->numOfPoints - 1, NULL, tailCompFn, NULL, 0);
7023
  }
7024
}
7025
#endif
7026

7027
int32_t tailFunction(SqlFunctionCtx* pCtx) {
×
7028
#if 0
7029
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
7030
  STailInfo*           pInfo = GET_ROWCELL_INTERBUF(pResInfo);
7031

7032
  SInputColumnInfoData* pInput = &pCtx->input;
7033
  TSKEY*                tsList = (int64_t*)pInput->pPTS->pData;
7034

7035
  SColumnInfoData* pInputCol = pInput->pData[0];
7036
  SColumnInfoData* pOutput = (SColumnInfoData*)pCtx->pOutput;
7037

7038
  int32_t startOffset = pCtx->offset;
7039
  if (pInfo->offset >= pInput->numOfRows) {
7040
    return 0;
7041
  } else {
7042
    pInfo->numOfPoints = TMIN(pInfo->numOfPoints, pInput->numOfRows - pInfo->offset);
7043
  }
7044
  for (int32_t i = pInput->startRowIndex; i < pInput->numOfRows + pInput->startRowIndex - pInfo->offset; i += 1) {
7045
    char* data = colDataGetData(pInputCol, i);
7046
    doTailAdd(pInfo, data, tsList[i], colDataIsNull_s(pInputCol, i));
7047
  }
7048

7049
  taosqsort(pInfo->pItems, pInfo->numOfPoints, POINTER_BYTES, NULL, tailCompFn);
7050

7051
  for (int32_t i = 0; i < pInfo->numOfPoints; ++i) {
7052
    int32_t    pos = startOffset + i;
7053
    STailItem* pItem = pInfo->pItems[i];
7054
    if (pItem->isNull) {
7055
      colDataSetNULL(pOutput, pos);
7056
    } else {
7057
      colDataSetVal(pOutput, pos, pItem->data, false);
7058
    }
7059
  }
7060

7061
  return pInfo->numOfPoints;
7062
#endif
7063
  return 0;
×
7064
}
7065

7066
int32_t tailFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
×
7067
#if 0
7068
  SResultRowEntryInfo* pEntryInfo = GET_RES_INFO(pCtx);
7069
  STailInfo*           pInfo = GET_ROWCELL_INTERBUF(pEntryInfo);
7070
  pEntryInfo->complete = true;
7071

7072
  int32_t type = pCtx->input.pData[0]->info.type;
7073
  int32_t slotId = pCtx->pExpr->base.resSchema.slotId;
7074

7075
  SColumnInfoData* pCol = taosArrayGet(pBlock->pDataBlock, slotId);
7076

7077
  // todo assign the tag value and the corresponding row data
7078
  int32_t currentRow = pBlock->info.rows;
7079
  for (int32_t i = 0; i < pEntryInfo->numOfRes; ++i) {
7080
    STailItem* pItem = pInfo->pItems[i];
7081
    colDataSetVal(pCol, currentRow, pItem->data, false);
7082
    currentRow += 1;
7083
  }
7084

7085
  return pEntryInfo->numOfRes;
7086
#endif
7087
  return 0;
×
7088
}
7089

7090
bool getUniqueFuncEnv(SFunctionNode* pFunc, SFuncExecEnv* pEnv) {
×
7091
#if 0
7092
  pEnv->calcMemSize = sizeof(SUniqueInfo) + UNIQUE_MAX_RESULT_SIZE;
7093
#endif
7094
  return true;
×
7095
}
7096

7097
int32_t uniqueFunctionSetup(SqlFunctionCtx* pCtx, SResultRowEntryInfo* pResInfo) {
×
7098
#if 0
7099
  if (!functionSetup(pCtx, pResInfo)) {
7100
    return false;
7101
  }
7102

7103
  SUniqueInfo* pInfo = GET_ROWCELL_INTERBUF(pResInfo);
7104
  pInfo->numOfPoints = 0;
7105
  pInfo->colType = pCtx->resDataInfo.type;
7106
  pInfo->colBytes = pCtx->resDataInfo.bytes;
7107
  if (pInfo->pHash != NULL) {
7108
    taosHashClear(pInfo->pHash);
7109
  } else {
7110
    pInfo->pHash = taosHashInit(64, taosGetDefaultHashFunction(TSDB_DATA_TYPE_BINARY), true, HASH_NO_LOCK);
7111
  }
7112
#endif
7113
  return TSDB_CODE_SUCCESS;
×
7114
}
7115

7116
#if 0
7117
static void doUniqueAdd(SUniqueInfo* pInfo, char* data, TSKEY ts, bool isNull) {
7118
  // handle null elements
7119
  if (isNull == true) {
7120
    int32_t      size = sizeof(SUniqueItem) + pInfo->colBytes;
7121
    SUniqueItem* pItem = (SUniqueItem*)(pInfo->pItems + pInfo->numOfPoints * size);
7122
    if (pInfo->hasNull == false && pItem->isNull == false) {
7123
      pItem->timestamp = ts;
7124
      pItem->isNull = true;
7125
      pInfo->numOfPoints++;
7126
      pInfo->hasNull = true;
7127
    } else if (pItem->timestamp > ts && pItem->isNull == true) {
7128
      pItem->timestamp = ts;
7129
    }
7130
    return;
7131
  }
7132

7133
  int32_t      hashKeyBytes = IS_VAR_DATA_TYPE(pInfo->colType) ? varDataTLen(data) : pInfo->colBytes;
7134
  SUniqueItem* pHashItem = taosHashGet(pInfo->pHash, data, hashKeyBytes);
7135
  if (pHashItem == NULL) {
7136
    int32_t      size = sizeof(SUniqueItem) + pInfo->colBytes;
7137
    SUniqueItem* pItem = (SUniqueItem*)(pInfo->pItems + pInfo->numOfPoints * size);
7138
    pItem->timestamp = ts;
7139
    memcpy(pItem->data, data, pInfo->colBytes);
7140

7141
    taosHashPut(pInfo->pHash, data, hashKeyBytes, (char*)pItem, sizeof(SUniqueItem*));
7142
    pInfo->numOfPoints++;
7143
  } else if (pHashItem->timestamp > ts) {
7144
    pHashItem->timestamp = ts;
7145
  }
7146
}
7147
#endif
7148

7149
int32_t uniqueFunction(SqlFunctionCtx* pCtx) {
×
7150
#if 0
7151
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
7152
  SUniqueInfo*         pInfo = GET_ROWCELL_INTERBUF(pResInfo);
7153

7154
  SInputColumnInfoData* pInput = &pCtx->input;
7155
  TSKEY*                tsList = (int64_t*)pInput->pPTS->pData;
7156

7157
  SColumnInfoData* pInputCol = pInput->pData[0];
7158
  SColumnInfoData* pTsOutput = pCtx->pTsOutput;
7159
  SColumnInfoData* pOutput = (SColumnInfoData*)pCtx->pOutput;
7160

7161
  int32_t startOffset = pCtx->offset;
7162
  for (int32_t i = pInput->startRowIndex; i < pInput->numOfRows + pInput->startRowIndex; ++i) {
7163
    char* data = colDataGetData(pInputCol, i);
7164
    doUniqueAdd(pInfo, data, tsList[i], colDataIsNull_s(pInputCol, i));
7165

7166
    if (sizeof(SUniqueInfo) + pInfo->numOfPoints * (sizeof(SUniqueItem) + pInfo->colBytes) >= UNIQUE_MAX_RESULT_SIZE) {
7167
      taosHashCleanup(pInfo->pHash);
7168
      return 0;
7169
    }
7170
  }
7171

7172
  for (int32_t i = 0; i < pInfo->numOfPoints; ++i) {
7173
    SUniqueItem* pItem = (SUniqueItem*)(pInfo->pItems + i * (sizeof(SUniqueItem) + pInfo->colBytes));
7174
    if (pItem->isNull == true) {
7175
      colDataSetNULL(pOutput, i);
7176
    } else {
7177
      colDataSetVal(pOutput, i, pItem->data, false);
7178
    }
7179
    if (pTsOutput != NULL) {
7180
      colDataSetInt64(pTsOutput, i, &pItem->timestamp);
7181
    }
7182
  }
7183

7184
  return pInfo->numOfPoints;
7185
#endif
7186
  return 0;
×
7187
}
7188

7189
bool getModeFuncEnv(SFunctionNode* pFunc, SFuncExecEnv* pEnv) {
857,075✔
7190
  pEnv->calcMemSize = sizeof(SModeInfo);
857,075✔
7191
  return true;
857,491✔
7192
}
7193

7194
int32_t modeFunctionSetup(SqlFunctionCtx* pCtx, SResultRowEntryInfo* pResInfo) {
1,045,720✔
7195
  if (pResInfo->initialized) {
1,045,720✔
7196
    return TSDB_CODE_SUCCESS;
×
7197
  }
7198
  if (TSDB_CODE_SUCCESS != functionSetup(pCtx, pResInfo)) {
1,045,720✔
7199
    return TSDB_CODE_FUNC_SETUP_ERROR;
×
7200
  }
7201

7202
  SModeInfo* pInfo = GET_ROWCELL_INTERBUF(pResInfo);
1,046,304✔
7203
  pInfo->colType = pCtx->resDataInfo.type;
1,046,304✔
7204
  pInfo->colBytes = pCtx->resDataInfo.bytes;
1,045,720✔
7205
  if (pInfo->pHash != NULL) {
1,045,720✔
7206
    taosHashClear(pInfo->pHash);
×
7207
  } else {
7208
    pInfo->pHash = taosHashInit(64, taosGetDefaultHashFunction(TSDB_DATA_TYPE_BINARY), true, HASH_NO_LOCK);
1,045,136✔
7209
    if (NULL == pInfo->pHash) {
1,046,304✔
7210
      return terrno;
×
7211
    }
7212
  }
7213
  pInfo->nullTupleSaved = false;
1,045,720✔
7214
  pInfo->nullTuplePos.pageId = -1;
1,045,720✔
7215

7216
  pInfo->buf = taosMemoryMalloc(pInfo->colBytes);
1,045,720✔
7217
  if (NULL == pInfo->buf) {
1,045,720✔
7218
    taosHashCleanup(pInfo->pHash);
×
7219
    pInfo->pHash = NULL;
×
7220
    return terrno;
×
7221
  }
7222
  pCtx->needCleanup = true;
1,045,720✔
7223
  return TSDB_CODE_SUCCESS;
1,045,136✔
7224
}
7225

7226
static void modeFunctionCleanup(SModeInfo* pInfo) {
1,826,260✔
7227
  taosHashCleanup(pInfo->pHash);
1,826,260✔
7228
  pInfo->pHash = NULL;
1,826,260✔
7229
  taosMemoryFreeClear(pInfo->buf);
1,826,260✔
7230
}
1,826,260✔
7231

7232
void modeFunctionCleanupExt(SqlFunctionCtx* pCtx) {
857,491✔
7233
  if (pCtx == NULL || GET_RES_INFO(pCtx) == NULL || GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx)) == NULL) {
857,491✔
7234
    return;
76,119✔
7235
  }
7236
  modeFunctionCleanup(GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx)));
781,372✔
7237
}
7238

7239
static int32_t saveModeTupleData(SqlFunctionCtx* pCtx, char* data, SModeInfo* pInfo, STuplePos* pPos) {
124,083,028✔
7240
  if (IS_VAR_DATA_TYPE(pInfo->colType)) {
124,083,028✔
7241
    if (pInfo->colType == TSDB_DATA_TYPE_JSON) {
3,173,549✔
7242
      (void)memcpy(pInfo->buf, data, getJsonValueLen(data));
304,128✔
7243
    } else if (IS_STR_DATA_BLOB(pInfo->colType)) {
2,871,917✔
7244
      (void)memcpy(pInfo->buf, data, blobDataTLen(data));
×
7245
    } else {
7246
      (void)memcpy(pInfo->buf, data, varDataTLen(data));
2,871,917✔
7247
    }
7248
  } else {
7249
    (void)memcpy(pInfo->buf, data, pInfo->colBytes);
120,912,447✔
7250
  }
7251

7252
  return doSaveTupleData(&pCtx->saveHandle, pInfo->buf, pInfo->colBytes, NULL, pPos, pCtx->pStore);
124,080,172✔
7253
}
7254

7255
static int32_t doModeAdd(SModeInfo* pInfo, int32_t rowIndex, SqlFunctionCtx* pCtx, char* data) {
265,642,045✔
7256
  int32_t code = TSDB_CODE_SUCCESS;
265,642,045✔
7257
  int32_t hashKeyBytes;
7258
  if (IS_VAR_DATA_TYPE(pInfo->colType)) {
265,642,045✔
7259
    hashKeyBytes = calcStrBytesByType(pInfo->colType, data);
3,346,260✔
7260
  } else {
7261
    hashKeyBytes = pInfo->colBytes;
262,296,145✔
7262
  }
7263

7264
  SModeItem* pHashItem = (SModeItem*)taosHashGet(pInfo->pHash, data, hashKeyBytes);
265,642,461✔
7265
  if (pHashItem == NULL) {
265,635,682✔
7266
    int32_t   size = sizeof(SModeItem);
124,082,196✔
7267
    SModeItem item = {0};
124,082,196✔
7268

7269
    item.count += 1;
124,082,612✔
7270
    code = saveModeTupleData(pCtx, data, pInfo, &item.dataPos);
124,082,612✔
7271
    if (code != TSDB_CODE_SUCCESS) {
124,017,114✔
7272
      return code;
×
7273
    }
7274

7275
    if (pCtx->subsidiaries.num > 0) {
124,017,114✔
7276
      code = saveTupleData(pCtx, rowIndex, pCtx->pSrcBlock, &item.tuplePos);
288,766✔
7277
      if (code != TSDB_CODE_SUCCESS) {
288,766✔
7278
        return code;
×
7279
      }
7280
    }
7281

7282
    code = taosHashPut(pInfo->pHash, data, hashKeyBytes, &item, sizeof(SModeItem));
124,073,282✔
7283
    if (code != TSDB_CODE_SUCCESS) {
124,090,223✔
7284
      return code;
×
7285
    }
7286
  } else {
7287
    pHashItem->count += 1;
141,553,486✔
7288
    if (pCtx->subsidiaries.num > 0) {
141,553,486✔
7289
      code = updateTupleData(pCtx, rowIndex, pCtx->pSrcBlock, &pHashItem->tuplePos);
3,695,406✔
7290
      if (code != TSDB_CODE_SUCCESS) {
3,695,406✔
7291
        return code;
×
7292
      }
7293
    }
7294
  }
7295

7296
  return code;
265,644,125✔
7297
}
7298

7299
int32_t modeFunction(SqlFunctionCtx* pCtx) {
2,142,677✔
7300
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
2,142,677✔
7301
  SModeInfo*           pInfo = GET_ROWCELL_INTERBUF(pResInfo);
2,142,677✔
7302

7303
  SInputColumnInfoData* pInput = &pCtx->input;
2,142,677✔
7304

7305
  SColumnInfoData* pInputCol = pInput->pData[0];
2,142,677✔
7306
  SColumnInfoData* pOutput = (SColumnInfoData*)pCtx->pOutput;
2,143,261✔
7307

7308
  int32_t numOfElems = 0;
2,142,677✔
7309
  int32_t startOffset = pCtx->offset;
2,142,677✔
7310
  for (int32_t i = pInput->startRowIndex; i < pInput->numOfRows + pInput->startRowIndex; ++i) {
345,782,000✔
7311
    if (colDataIsNull_s(pInputCol, i)) {
687,280,836✔
7312
      continue;
77,999,556✔
7313
    }
7314
    numOfElems++;
265,643,541✔
7315

7316
    char*   data = colDataGetData(pInputCol, i);
265,643,541✔
7317
    int32_t code = doModeAdd(pInfo, i, pCtx, data);
265,644,125✔
7318
    if (code != TSDB_CODE_SUCCESS) {
265,644,125✔
7319
      modeFunctionCleanup(pInfo);
3,774✔
7320
      return code;
×
7321
    }
7322
  }
7323

7324
  if (numOfElems == 0 && pCtx->subsidiaries.num > 0 && !pInfo->nullTupleSaved) {
2,143,261✔
7325
    int32_t code = saveTupleData(pCtx, pInput->startRowIndex, pCtx->pSrcBlock, &pInfo->nullTuplePos);
4,940✔
7326
    if (code != TSDB_CODE_SUCCESS) {
4,940✔
7327
      modeFunctionCleanup(pInfo);
×
7328
      return code;
×
7329
    }
7330
    pInfo->nullTupleSaved = true;
4,940✔
7331
  }
7332

7333
  SET_VAL(pResInfo, numOfElems, 1);
2,143,261✔
7334

7335
  return TSDB_CODE_SUCCESS;
2,143,261✔
7336
}
7337

7338
int32_t modeFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
1,044,888✔
7339
  int32_t              code = TSDB_CODE_SUCCESS;
1,044,888✔
7340
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
1,044,888✔
7341
  SModeInfo*           pInfo = GET_ROWCELL_INTERBUF(pResInfo);
1,044,888✔
7342
  int32_t              slotId = pCtx->pExpr->base.resSchema.slotId;
1,044,888✔
7343
  SColumnInfoData*     pCol = taosArrayGet(pBlock->pDataBlock, slotId);
1,044,888✔
7344
  int32_t              currentRow = pBlock->info.rows;
1,044,888✔
7345
  if (NULL == pCol) {
1,044,888✔
7346
    modeFunctionCleanup(pInfo);
×
7347
    return TSDB_CODE_OUT_OF_RANGE;
×
7348
  }
7349

7350
  STuplePos resDataPos, resTuplePos;
1,044,888✔
7351
  int32_t   maxCount = 0;
1,044,888✔
7352

7353
  void* pIter = taosHashIterate(pInfo->pHash, NULL);
1,044,888✔
7354
  while (pIter != NULL) {
125,133,751✔
7355
    SModeItem* pItem = (SModeItem*)pIter;
124,088,863✔
7356
    if (pItem->count >= maxCount) {
124,088,863✔
7357
      maxCount = pItem->count;
119,073,161✔
7358
      resDataPos = pItem->dataPos;
119,073,161✔
7359
      resTuplePos = pItem->tuplePos;
119,073,161✔
7360
    }
7361

7362
    pIter = taosHashIterate(pInfo->pHash, pIter);
124,088,391✔
7363
  }
7364

7365
  if (maxCount != 0) {
1,044,888✔
7366
    char* pData = NULL;
614,194✔
7367
    code = loadTupleData(pCtx, &resDataPos, &pData);
614,194✔
7368
    if (pData == NULL || TSDB_CODE_SUCCESS != code) {
614,194✔
7369
      code = terrno = TSDB_CODE_NOT_FOUND;
×
7370
      qError("Load tuple data failed since %s, groupId:%" PRIu64 ", ts:%" PRId64, terrstr(),
×
7371
             resDataPos.streamTupleKey.groupId, resDataPos.streamTupleKey.ts);
7372
      modeFunctionCleanup(pInfo);
×
7373
      return code;
×
7374
    }
7375

7376
    code = colDataSetVal(pCol, currentRow, pData, false);
614,194✔
7377
    if (TSDB_CODE_SUCCESS != code) {
614,194✔
7378
      modeFunctionCleanup(pInfo);
×
7379
      return code;
×
7380
    }
7381
    code = setSelectivityValue(pCtx, pBlock, &resTuplePos, currentRow);
614,194✔
7382
  } else {
7383
    colDataSetNULL(pCol, currentRow);
430,694✔
7384
    code = setSelectivityValue(pCtx, pBlock, &pInfo->nullTuplePos, currentRow);
430,694✔
7385
  }
7386

7387
  modeFunctionCleanup(pInfo);
1,044,888✔
7388

7389
  return code;
1,044,888✔
7390
}
7391

7392
bool getTwaFuncEnv(struct SFunctionNode* pFunc, SFuncExecEnv* pEnv) {
357,131✔
7393
  pEnv->calcMemSize = sizeof(STwaInfo);
357,131✔
7394
  return true;
357,131✔
7395
}
7396

7397
int32_t twaFunctionSetup(SqlFunctionCtx* pCtx, SResultRowEntryInfo* pResultInfo) {
8,607,226✔
7398
  if (pResultInfo->initialized) {
8,607,226✔
7399
    return TSDB_CODE_SUCCESS;
×
7400
  }
7401
  if (TSDB_CODE_SUCCESS != functionSetup(pCtx, pResultInfo)) {
8,607,226✔
7402
    return TSDB_CODE_FUNC_SETUP_ERROR;
×
7403
  }
7404

7405
  STwaInfo* pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
8,607,226✔
7406
  pInfo->numOfElems = 0;
8,607,226✔
7407
  pInfo->p.key = INT64_MIN;
8,607,226✔
7408
  pInfo->win = TSWINDOW_INITIALIZER;
8,607,226✔
7409
  return TSDB_CODE_SUCCESS;
8,607,226✔
7410
}
7411

7412
static double twa_get_area(SPoint1 s, SPoint1 e) {
207,455,174✔
7413
  if (e.key == INT64_MAX || s.key == INT64_MIN) {
207,455,174✔
7414
    return 0;
×
7415
  }
7416

7417
  if ((s.val >= 0 && e.val >= 0) || (s.val <= 0 && e.val <= 0)) {
207,456,306✔
7418
    return (s.val + e.val) * (e.key - s.key) / 2;
189,787,108✔
7419
  }
7420

7421
  double x = (s.key * e.val - e.key * s.val) / (e.val - s.val);
17,669,198✔
7422
  double val = (s.val * (x - s.key) + e.val * (e.key - x)) / 2;
17,669,198✔
7423
  return val;
17,669,198✔
7424
}
7425

7426
int32_t twaFunction(SqlFunctionCtx* pCtx) {
8,702,923✔
7427
  int32_t               code = TSDB_CODE_SUCCESS;
8,702,923✔
7428
  SInputColumnInfoData* pInput = &pCtx->input;
8,702,923✔
7429
  SColumnInfoData*      pInputCol = pInput->pData[0];
8,702,923✔
7430

7431
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
8,702,923✔
7432
  STwaInfo*            pInfo = GET_ROWCELL_INTERBUF(pResInfo);
8,702,923✔
7433
  SPoint1*             last = &pInfo->p;
8,702,923✔
7434

7435
  if (IS_NULL_TYPE(pInputCol->info.type)) {
8,702,923✔
7436
    pInfo->numOfElems = 0;
×
7437
    goto _twa_over;
×
7438
  }
7439

7440
  funcInputUpdate(pCtx);
8,702,923✔
7441
  SFuncInputRow row = {0};
8,702,923✔
7442
  bool          result = false;
8,702,923✔
7443
  if (pCtx->start.key != INT64_MIN && last->key == INT64_MIN) {
8,702,923✔
7444
    while (1) {
7445
      code = funcInputGetNextRow(pCtx, &row, &result);
5,781,421✔
7446
      if (TSDB_CODE_SUCCESS != code) {
5,781,421✔
7447
        return code;
×
7448
      }
7449
      if (!result) {
5,781,421✔
7450
        break;
824✔
7451
      }
7452
      if (row.isDataNull) {
5,780,597✔
7453
        continue;
824✔
7454
      }
7455

7456
      last->key = row.ts;
5,779,773✔
7457

7458
      GET_TYPED_DATA(last->val, double, pInputCol->info.type, row.pData, typeGetTypeModFromColInfo(&pInputCol->info));
5,779,773✔
7459

7460
      pInfo->dOutput += twa_get_area(pCtx->start, *last);
5,779,773✔
7461
      pInfo->win.skey = pCtx->start.key;
5,779,773✔
7462
      pInfo->numOfElems++;
5,779,773✔
7463
      break;
5,779,773✔
7464
    }
7465
  } else if (pInfo->p.key == INT64_MIN) {
2,922,326✔
7466
    while (1) {
7467
      code = funcInputGetNextRow(pCtx, &row, &result);
14,011,215✔
7468
      if (TSDB_CODE_SUCCESS != code) {
14,011,215✔
7469
        return code;
×
7470
      }
7471
      if (!result) {
14,011,215✔
7472
        break;
1,016,883✔
7473
      }
7474
      if (row.isDataNull) {
12,994,332✔
7475
        continue;
11,142,332✔
7476
      }
7477

7478
      last->key = row.ts;
1,852,000✔
7479

7480
      GET_TYPED_DATA(last->val, double, pInputCol->info.type, row.pData, typeGetTypeModFromColInfo(&pInputCol->info));
1,852,000✔
7481

7482
      pInfo->win.skey = last->key;
1,852,000✔
7483
      pInfo->numOfElems++;
1,852,000✔
7484
      break;
1,852,000✔
7485
    }
7486
  }
7487

7488
  SPoint1 st = {0};
8,702,923✔
7489

7490
  // calculate the value of
7491
  while (1) {
7492
    code = funcInputGetNextRow(pCtx, &row, &result);
204,630,618✔
7493
    if (TSDB_CODE_SUCCESS != code) {
204,638,442✔
7494
      return code;
×
7495
    }
7496
    if (!result) {
204,638,442✔
7497
      break;
8,702,923✔
7498
    }
7499
    if (row.isDataNull) {
195,935,519✔
7500
      continue;
61,614✔
7501
    }
7502
    pInfo->numOfElems++;
195,873,905✔
7503
    switch (pInputCol->info.type) {
195,874,815✔
7504
      case TSDB_DATA_TYPE_TINYINT: {
14,613,741✔
7505
        INIT_INTP_POINT(st, row.ts, *(int8_t*)row.pData);
14,613,741✔
7506
        break;
14,613,741✔
7507
      }
7508
      case TSDB_DATA_TYPE_SMALLINT: {
15,331,273✔
7509
        INIT_INTP_POINT(st, row.ts, *(int16_t*)row.pData);
15,331,273✔
7510
        break;
15,331,273✔
7511
      }
7512
      case TSDB_DATA_TYPE_INT: {
83,833,714✔
7513
        INIT_INTP_POINT(st, row.ts, *(int32_t*)row.pData);
83,833,714✔
7514
        break;
83,833,714✔
7515
      }
7516
      case TSDB_DATA_TYPE_BIGINT: {
16,308,614✔
7517
        INIT_INTP_POINT(st, row.ts, *(int64_t*)row.pData);
16,308,614✔
7518
        break;
16,308,614✔
7519
      }
7520
      case TSDB_DATA_TYPE_FLOAT: {
12,539,870✔
7521
        INIT_INTP_POINT(st, row.ts, *(float_t*)row.pData);
12,539,870✔
7522
        break;
12,539,870✔
7523
      }
7524
      case TSDB_DATA_TYPE_DOUBLE: {
14,502,471✔
7525
        INIT_INTP_POINT(st, row.ts, *(double*)row.pData);
14,502,471✔
7526
        break;
14,501,982✔
7527
      }
7528
      case TSDB_DATA_TYPE_UTINYINT: {
9,898,638✔
7529
        INIT_INTP_POINT(st, row.ts, *(uint8_t*)row.pData);
9,898,638✔
7530
        break;
9,900,105✔
7531
      }
7532
      case TSDB_DATA_TYPE_USMALLINT: {
9,899,616✔
7533
        INIT_INTP_POINT(st, row.ts, *(uint16_t*)row.pData);
9,899,616✔
7534
        break;
9,899,616✔
7535
      }
7536
      case TSDB_DATA_TYPE_UINT: {
9,980,566✔
7537
        INIT_INTP_POINT(st, row.ts, *(uint32_t*)row.pData);
9,980,566✔
7538
        break;
9,980,566✔
7539
      }
7540
      case TSDB_DATA_TYPE_UBIGINT: {
8,964,913✔
7541
        INIT_INTP_POINT(st, row.ts, *(uint64_t*)row.pData);
8,964,913✔
7542
        break;
8,964,913✔
7543
      }
7544
      default: {
×
7545
        return TSDB_CODE_FUNC_FUNTION_PARA_TYPE;
×
7546
      }
7547
    }
7548
    if (pInfo->p.key == st.key) {
195,874,394✔
7549
      return TSDB_CODE_FUNC_DUP_TIMESTAMP;
×
7550
    }
7551

7552
    pInfo->dOutput += twa_get_area(pInfo->p, st);
195,874,394✔
7553
    pInfo->p = st;
195,864,614✔
7554
  }
7555

7556
  // the last interpolated time window value
7557
  if (pCtx->end.key != INT64_MIN) {
8,702,923✔
7558
    pInfo->dOutput += twa_get_area(pInfo->p, pCtx->end);
5,793,183✔
7559
    pInfo->p = pCtx->end;
5,793,183✔
7560
    pInfo->numOfElems += 1;
5,793,183✔
7561
  }
7562

7563
  pInfo->win.ekey = pInfo->p.key;
8,702,923✔
7564

7565
_twa_over:
8,702,923✔
7566
  SET_VAL(pResInfo, 1, 1);
8,702,923✔
7567
  return TSDB_CODE_SUCCESS;
8,702,923✔
7568
}
7569

7570
/*
7571
 * To copy the input to interResBuf to avoid the input buffer space be over writen
7572
 * by next input data. The TWA function only applies to each table, so no merge procedure
7573
 * is required, we simply copy to the resut ot interResBuffer.
7574
 */
7575
// void twa_function_copy(SQLFunctionCtx *pCtx) {
7576
//   SResultRowEntryInfo *pResInfo = GET_RES_INFO(pCtx);
7577
//
7578
//   memcpy(GET_ROWCELL_INTERBUF(pResInfo), pCtx->pInput, (size_t)pCtx->inputBytes);
7579
//   pResInfo->hasResult = ((STwaInfo *)pCtx->pInput)->hasResult;
7580
// }
7581

7582
int32_t twaFinalize(struct SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
8,606,264✔
7583
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
8,606,264✔
7584

7585
  STwaInfo* pInfo = (STwaInfo*)GET_ROWCELL_INTERBUF(pResInfo);
8,606,264✔
7586
  if (pInfo->numOfElems == 0) {
8,606,264✔
7587
    pResInfo->numOfRes = 0;
973,667✔
7588
  } else {
7589
    if (pInfo->win.ekey == pInfo->win.skey) {
7,632,597✔
7590
      pInfo->dTwaRes = pInfo->p.val;
901,974✔
7591
    } else if (pInfo->win.ekey == INT64_MAX || pInfo->win.skey == INT64_MIN) {  // no data in timewindow
6,730,623✔
7592
      pInfo->dTwaRes = 0;
824✔
7593
    } else {
7594
      pInfo->dTwaRes = pInfo->dOutput / (pInfo->win.ekey - pInfo->win.skey);
6,729,799✔
7595
    }
7596

7597
    pResInfo->numOfRes = 1;
7,632,108✔
7598
  }
7599

7600
  return functionFinalize(pCtx, pBlock);
8,605,775✔
7601
}
7602

7603
int32_t blockDistSetup(SqlFunctionCtx* pCtx, SResultRowEntryInfo* pResultInfo) {
3,299✔
7604
  if (pResultInfo->initialized) {
3,299✔
7605
    return TSDB_CODE_SUCCESS;
×
7606
  }
7607
  if (TSDB_CODE_SUCCESS != functionSetup(pCtx, pResultInfo)) {
3,299✔
7608
    return TSDB_CODE_FUNC_SETUP_ERROR;
×
7609
  }
7610

7611
  STableBlockDistInfo* pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
3,299✔
7612
  pInfo->minRows = INT32_MAX;
3,299✔
7613
  return TSDB_CODE_SUCCESS;
3,299✔
7614
}
7615

7616
int32_t blockDistFunction(SqlFunctionCtx* pCtx) {
6,284✔
7617
  const int32_t BLOCK_DIST_RESULT_ROWS = 25;
6,284✔
7618

7619
  SInputColumnInfoData* pInput = &pCtx->input;
6,284✔
7620
  SColumnInfoData*      pInputCol = pInput->pData[0];
6,284✔
7621
  SResultRowEntryInfo*  pResInfo = GET_RES_INFO(pCtx);
6,284✔
7622
  STableBlockDistInfo*  pDistInfo = GET_ROWCELL_INTERBUF(pResInfo);
6,284✔
7623

7624
  STableBlockDistInfo p1 = {0};
6,284✔
7625
  if (tDeserializeBlockDistInfo(varDataVal(pInputCol->pData), varDataLen(pInputCol->pData), &p1) < 0) {
6,284✔
7626
    qError("failed to deserialize block dist info");
×
7627
    return TSDB_CODE_FAILED;
×
7628
  }
7629

7630
  pDistInfo->numOfBlocks += p1.numOfBlocks;
6,284✔
7631
  pDistInfo->numOfTables += p1.numOfTables;
6,284✔
7632
  pDistInfo->numOfInmemRows += p1.numOfInmemRows;
6,284✔
7633
  pDistInfo->numOfSttRows += p1.numOfSttRows;
6,284✔
7634
  pDistInfo->totalSize += p1.totalSize;
6,284✔
7635
  pDistInfo->totalRows += p1.totalRows;
6,284✔
7636
  pDistInfo->numOfFiles += p1.numOfFiles;
6,284✔
7637

7638
  pDistInfo->defMinRows = p1.defMinRows;
6,284✔
7639
  pDistInfo->defMaxRows = p1.defMaxRows;
6,284✔
7640
  pDistInfo->rowSize = p1.rowSize;
6,284✔
7641

7642
  if (pDistInfo->minRows > p1.minRows) {
6,284✔
7643
    pDistInfo->minRows = p1.minRows;
1,411✔
7644
  }
7645
  if (pDistInfo->maxRows < p1.maxRows) {
6,284✔
7646
    pDistInfo->maxRows = p1.maxRows;
1,411✔
7647
  }
7648
  pDistInfo->numOfVgroups += (p1.numOfTables != 0 ? 1 : 0);
6,284✔
7649
  for (int32_t i = 0; i < tListLen(pDistInfo->blockRowsHisto); ++i) {
131,964✔
7650
    pDistInfo->blockRowsHisto[i] += p1.blockRowsHisto[i];
125,680✔
7651
  }
7652
  for (int32_t i = 0; i < tListLen(pDistInfo->blockRowsHistoFixed); ++i) {
56,556✔
7653
    pDistInfo->blockRowsHistoFixed[i] += p1.blockRowsHistoFixed[i];
50,272✔
7654
  }
7655

7656
  pResInfo->numOfRes = BLOCK_DIST_RESULT_ROWS;  // default output rows
6,284✔
7657
  return TSDB_CODE_SUCCESS;
6,284✔
7658
}
7659

7660
int32_t tSerializeBlockDistInfo(void* buf, int32_t bufLen, const STableBlockDistInfo* pInfo) {
12,568✔
7661
  SEncoder encoder = {0};
12,568✔
7662
  int32_t  code = 0;
12,568✔
7663
  int32_t  lino;
7664
  int32_t  tlen;
7665
  tEncoderInit(&encoder, buf, bufLen);
12,568✔
7666

7667
  TAOS_CHECK_EXIT(tStartEncode(&encoder));
12,568✔
7668
  TAOS_CHECK_EXIT(tEncodeU32(&encoder, pInfo->rowSize));
25,136✔
7669

7670
  TAOS_CHECK_EXIT(tEncodeU16(&encoder, pInfo->numOfFiles));
25,136✔
7671
  TAOS_CHECK_EXIT(tEncodeU32(&encoder, pInfo->numOfBlocks));
25,136✔
7672
  TAOS_CHECK_EXIT(tEncodeU32(&encoder, pInfo->numOfTables));
25,136✔
7673

7674
  TAOS_CHECK_EXIT(tEncodeU64(&encoder, pInfo->totalSize));
25,136✔
7675
  TAOS_CHECK_EXIT(tEncodeU64(&encoder, pInfo->totalRows));
25,136✔
7676
  TAOS_CHECK_EXIT(tEncodeI32(&encoder, pInfo->maxRows));
25,136✔
7677
  TAOS_CHECK_EXIT(tEncodeI32(&encoder, pInfo->minRows));
25,136✔
7678
  TAOS_CHECK_EXIT(tEncodeI32(&encoder, pInfo->defMaxRows));
25,136✔
7679
  TAOS_CHECK_EXIT(tEncodeI32(&encoder, pInfo->defMinRows));
25,136✔
7680
  TAOS_CHECK_EXIT(tEncodeU32(&encoder, pInfo->numOfInmemRows));
25,136✔
7681
  TAOS_CHECK_EXIT(tEncodeU32(&encoder, pInfo->numOfSttRows));
25,136✔
7682
  TAOS_CHECK_EXIT(tEncodeU32(&encoder, pInfo->numOfVgroups));
25,136✔
7683

7684
  for (int32_t i = 0; i < tListLen(pInfo->blockRowsHisto); ++i) {
263,928✔
7685
    TAOS_CHECK_EXIT(tEncodeI32(&encoder, pInfo->blockRowsHisto[i]));
502,720✔
7686
  }
7687

7688
  for (int32_t i = 0; i < tListLen(pInfo->blockRowsHistoFixed); ++i) {
113,112✔
7689
    TAOS_CHECK_EXIT(tEncodeI32(&encoder, pInfo->blockRowsHistoFixed[i]));
201,088✔
7690
  }
7691

7692
  tEndEncode(&encoder);
12,568✔
7693

7694
_exit:
12,568✔
7695
  if (code) {
12,568✔
7696
    tlen = code;
×
7697
  } else {
7698
    tlen = encoder.pos;
12,568✔
7699
  }
7700
  tEncoderClear(&encoder);
12,568✔
7701
  return tlen;
12,568✔
7702
}
7703

7704
int32_t tDeserializeBlockDistInfo(void* buf, int32_t bufLen, STableBlockDistInfo* pInfo) {
6,284✔
7705
  SDecoder decoder = {0};
6,284✔
7706
  int32_t  code = 0;
6,284✔
7707
  int32_t  lino;
7708
  tDecoderInit(&decoder, buf, bufLen);
6,284✔
7709

7710
  TAOS_CHECK_EXIT(tStartDecode(&decoder));
6,284✔
7711
  TAOS_CHECK_EXIT(tDecodeU32(&decoder, &pInfo->rowSize));
12,568✔
7712

7713
  TAOS_CHECK_EXIT(tDecodeU16(&decoder, &pInfo->numOfFiles));
12,568✔
7714
  TAOS_CHECK_EXIT(tDecodeU32(&decoder, &pInfo->numOfBlocks));
12,568✔
7715
  TAOS_CHECK_EXIT(tDecodeU32(&decoder, &pInfo->numOfTables));
12,568✔
7716

7717
  TAOS_CHECK_EXIT(tDecodeU64(&decoder, &pInfo->totalSize));
12,568✔
7718
  TAOS_CHECK_EXIT(tDecodeU64(&decoder, &pInfo->totalRows));
12,568✔
7719
  TAOS_CHECK_EXIT(tDecodeI32(&decoder, &pInfo->maxRows));
12,568✔
7720
  TAOS_CHECK_EXIT(tDecodeI32(&decoder, &pInfo->minRows));
12,568✔
7721
  TAOS_CHECK_EXIT(tDecodeI32(&decoder, &pInfo->defMaxRows));
12,568✔
7722
  TAOS_CHECK_EXIT(tDecodeI32(&decoder, &pInfo->defMinRows));
12,568✔
7723
  TAOS_CHECK_EXIT(tDecodeU32(&decoder, &pInfo->numOfInmemRows));
12,568✔
7724
  TAOS_CHECK_EXIT(tDecodeU32(&decoder, &pInfo->numOfSttRows));
12,568✔
7725
  TAOS_CHECK_EXIT(tDecodeU32(&decoder, &pInfo->numOfVgroups));
12,568✔
7726

7727
  for (int32_t i = 0; i < tListLen(pInfo->blockRowsHisto); ++i) {
131,964✔
7728
    TAOS_CHECK_EXIT(tDecodeI32(&decoder, &pInfo->blockRowsHisto[i]));
251,360✔
7729
  }
7730

7731
  if (!tDecodeIsEnd(&decoder)) {
6,284✔
7732
    for (int32_t i = 0; i < tListLen(pInfo->blockRowsHistoFixed); ++i) {
56,556✔
7733
      TAOS_CHECK_EXIT(tDecodeI32(&decoder, &pInfo->blockRowsHistoFixed[i]));
100,544✔
7734
    }
7735
  }
7736

7737
_exit:
6,284✔
7738
  tDecoderClear(&decoder);
6,284✔
7739
  return code;
6,284✔
7740
}
7741

7742
int32_t blockDistFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
3,299✔
7743
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
3,299✔
7744
  STableBlockDistInfo* pData = GET_ROWCELL_INTERBUF(pResInfo);
3,299✔
7745

7746
  SColumnInfoData* pColInfo = taosArrayGet(pBlock->pDataBlock, 0);
3,299✔
7747
  if (NULL == pColInfo) {
3,299✔
7748
    return TSDB_CODE_OUT_OF_RANGE;
×
7749
  }
7750

7751
  if (pData->totalRows == 0) {
3,299✔
7752
    pData->minRows = 0;
1,888✔
7753
  }
7754

7755
  int32_t row = 0;
3,299✔
7756
  char    st[256] = {0};
3,299✔
7757
  double  averageSize = 0;
3,299✔
7758
  if (pData->numOfBlocks != 0) {
3,299✔
7759
    averageSize = ((double)pData->totalSize) / pData->numOfBlocks;
1,411✔
7760
  }
7761
  uint64_t totalRawSize = pData->totalRows * pData->rowSize;
3,299✔
7762
  double   compRatio = 0;
3,299✔
7763
  if (totalRawSize != 0) {
3,299✔
7764
    compRatio = pData->totalSize * 100 / (double)totalRawSize;
1,411✔
7765
  }
7766

7767
  int32_t len = snprintf(varDataVal(st), sizeof(st) - VARSTR_HEADER_SIZE,
3,299✔
7768
                         "Total_Blocks=[%d] Total_Size=[%.2f KiB] Average_size=[%.2f KiB] Compression_Ratio=[%.2f %c]",
7769
                         pData->numOfBlocks, pData->totalSize / 1024.0, averageSize / 1024.0, compRatio, '%');
3,299✔
7770

7771
  varDataSetLen(st, len);
3,299✔
7772
  int32_t code = colDataSetVal(pColInfo, row++, st, false);
3,299✔
7773
  if (TSDB_CODE_SUCCESS != code) {
3,299✔
7774
    return code;
×
7775
  }
7776

7777
  int64_t avgRows = 0;
3,299✔
7778
  if (pData->numOfBlocks > 0) {
3,299✔
7779
    avgRows = pData->totalRows / pData->numOfBlocks;
1,411✔
7780
  }
7781

7782
  len = snprintf(varDataVal(st), sizeof(st) - VARSTR_HEADER_SIZE,
3,299✔
7783
                 "Block_Rows=[%" PRId64 "] MinRows=[%d] MaxRows=[%d] AvgRows=[%" PRId64 "]", pData->totalRows,
7784
                 pData->minRows, pData->maxRows, avgRows);
7785
  varDataSetLen(st, len);
3,299✔
7786
  code = colDataSetVal(pColInfo, row++, st, false);
3,299✔
7787
  if (TSDB_CODE_SUCCESS != code) {
3,299✔
7788
    return code;
×
7789
  }
7790

7791
  len = snprintf(varDataVal(st), sizeof(st) - VARSTR_HEADER_SIZE, "Inmem_Rows=[%u] Stt_Rows=[%u] ",
3,299✔
7792
                 pData->numOfInmemRows, pData->numOfSttRows);
7793
  varDataSetLen(st, len);
3,299✔
7794
  code = colDataSetVal(pColInfo, row++, st, false);
3,299✔
7795
  if (TSDB_CODE_SUCCESS != code) {
3,299✔
7796
    return code;
×
7797
  }
7798

7799
  len = snprintf(varDataVal(st), sizeof(st) - VARSTR_HEADER_SIZE,
6,598✔
7800
                 "Total_Tables=[%d] Total_Filesets=[%d] Total_Vgroups=[%d]", pData->numOfTables, pData->numOfFiles,
3,299✔
7801
                 pData->numOfVgroups);
7802

7803
  varDataSetLen(st, len);
3,299✔
7804
  code = colDataSetVal(pColInfo, row++, st, false);
3,299✔
7805
  if (TSDB_CODE_SUCCESS != code) {
3,299✔
7806
    return code;
×
7807
  }
7808

7809
  len = snprintf(varDataVal(st), sizeof(st) - VARSTR_HEADER_SIZE,
3,299✔
7810
                 "--------------------------------------------------------------------------------");
7811
  varDataSetLen(st, len);
3,299✔
7812
  code = colDataSetVal(pColInfo, row++, st, false);
3,299✔
7813
  if (TSDB_CODE_SUCCESS != code) {
3,299✔
7814
    return code;
×
7815
  }
7816

7817
  int32_t maxVal = 0;
3,299✔
7818
  int32_t minVal = INT32_MAX;
3,299✔
7819
  for (int32_t i = 0; i < tListLen(pData->blockRowsHisto); ++i) {
69,279✔
7820
    if (maxVal < pData->blockRowsHisto[i]) {
65,980✔
7821
      maxVal = pData->blockRowsHisto[i];
2,027✔
7822
    }
7823

7824
    if (minVal > pData->blockRowsHisto[i]) {
65,980✔
7825
      minVal = pData->blockRowsHisto[i];
4,094✔
7826
    }
7827
  }
7828

7829
  // maximum number of step is 80
7830
  double factor = pData->numOfBlocks / 80.0;
3,299✔
7831

7832
  int32_t numOfBuckets = sizeof(pData->blockRowsHisto) / sizeof(pData->blockRowsHisto[0]);
3,299✔
7833
  int32_t bucketRange = ceil(((double)(pData->defMaxRows - pData->defMinRows)) / numOfBuckets);
3,299✔
7834

7835
  for (int32_t i = 0; i < tListLen(pData->blockRowsHisto); ++i) {
69,279✔
7836
    len =
7837
        snprintf(varDataVal(st), sizeof(st) - VARSTR_HEADER_SIZE, "%04d |", pData->defMinRows + bucketRange * (i + 1));
65,980✔
7838

7839
    int32_t num = 0;
65,980✔
7840
    if (pData->blockRowsHisto[i] > 0) {
65,980✔
7841
      num = (pData->blockRowsHisto[i]) / factor;
3,259✔
7842
    }
7843

7844
    for (int32_t j = 0; j < num; ++j) {
178,244✔
7845
      int32_t x = snprintf(varDataVal(st) + len, sizeof(st) - VARSTR_HEADER_SIZE - len, "%c", '|');
112,264✔
7846
      len += x;
112,264✔
7847
    }
7848

7849
    if (pData->blockRowsHisto[i] > 0) {
65,980✔
7850
      double v = pData->blockRowsHisto[i] * 100.0 / pData->numOfBlocks;
3,259✔
7851
      len += snprintf(varDataVal(st) + len, sizeof(st) - VARSTR_HEADER_SIZE - len, "  %d (%.2f%c)",
3,259✔
7852
                      pData->blockRowsHisto[i], v, '%');
3,259✔
7853
    }
7854

7855
    varDataSetLen(st, len);
65,980✔
7856
    code = colDataSetVal(pColInfo, row++, st, false);
65,980✔
7857
    if (TSDB_CODE_SUCCESS != code) {
65,980✔
7858
      return code;
×
7859
    }
7860
  }
7861

7862
  return TSDB_CODE_SUCCESS;
3,299✔
7863
}
7864
int32_t blockDBUsageSetup(SqlFunctionCtx* pCtx, SResultRowEntryInfo* pResultInfo) {
429✔
7865
  if (pResultInfo->initialized) {
429✔
7866
    return TSDB_CODE_SUCCESS;
×
7867
  }
7868
  if (TSDB_CODE_SUCCESS != functionSetup(pCtx, pResultInfo)) {
429✔
7869
    return TSDB_CODE_FUNC_SETUP_ERROR;
×
7870
  }
7871

7872
  SDBBlockUsageInfo* pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
429✔
7873
  return TSDB_CODE_SUCCESS;
429✔
7874
}
7875
int32_t blockDBUsageFunction(SqlFunctionCtx* pCtx) {
858✔
7876
  const int32_t BLOCK_DISK_USAGE_RESULT_ROWS = 2;
858✔
7877

7878
  SInputColumnInfoData* pInput = &pCtx->input;
858✔
7879
  SColumnInfoData*      pInputCol = pInput->pData[0];
858✔
7880
  SResultRowEntryInfo*  pResInfo = GET_RES_INFO(pCtx);
858✔
7881
  SDBBlockUsageInfo*    pDistInfo = GET_ROWCELL_INTERBUF(pResInfo);
858✔
7882

7883
  SDBBlockUsageInfo p1 = {0};
858✔
7884
  if (tDeserializeBlockDbUsage(varDataVal(pInputCol->pData), varDataLen(pInputCol->pData), &p1) < 0) {
858✔
7885
    qError("failed to deserialize block dist info");
×
7886
    return TSDB_CODE_FAILED;
×
7887
  }
7888

7889
  pDistInfo->dataInDiskSize += p1.dataInDiskSize;
858✔
7890
  pDistInfo->walInDiskSize += p1.walInDiskSize;
858✔
7891
  pDistInfo->rawDataSize += p1.rawDataSize;
858✔
7892
  pResInfo->numOfRes = BLOCK_DISK_USAGE_RESULT_ROWS;  // default output rows
858✔
7893
  return TSDB_CODE_SUCCESS;
858✔
7894
}
7895

7896
int32_t tSerializeBlockDbUsage(void* buf, int32_t bufLen, const SDBBlockUsageInfo* pInfo) {
1,716✔
7897
  SEncoder encoder = {0};
1,716✔
7898
  int32_t  code = 0;
1,716✔
7899
  int32_t  lino;
7900
  int32_t  tlen;
7901
  tEncoderInit(&encoder, buf, bufLen);
1,716✔
7902

7903
  TAOS_CHECK_EXIT(tStartEncode(&encoder));
1,716✔
7904

7905
  TAOS_CHECK_EXIT(tEncodeU64(&encoder, pInfo->dataInDiskSize));
3,432✔
7906
  TAOS_CHECK_EXIT(tEncodeU64(&encoder, pInfo->walInDiskSize));
3,432✔
7907
  TAOS_CHECK_EXIT(tEncodeU64(&encoder, pInfo->rawDataSize));
3,432✔
7908

7909
  tEndEncode(&encoder);
1,716✔
7910

7911
_exit:
1,716✔
7912
  if (code) {
1,716✔
7913
    tlen = code;
×
7914
  } else {
7915
    tlen = encoder.pos;
1,716✔
7916
  }
7917
  tEncoderClear(&encoder);
1,716✔
7918
  return tlen;
1,716✔
7919
}
7920
int32_t tDeserializeBlockDbUsage(void* buf, int32_t bufLen, SDBBlockUsageInfo* pInfo) {
858✔
7921
  SDecoder decoder = {0};
858✔
7922
  int32_t  code = 0;
858✔
7923
  int32_t  lino;
7924
  tDecoderInit(&decoder, buf, bufLen);
858✔
7925

7926
  TAOS_CHECK_EXIT(tStartDecode(&decoder));
858✔
7927
  TAOS_CHECK_EXIT(tDecodeU64(&decoder, &pInfo->dataInDiskSize));
1,716✔
7928
  TAOS_CHECK_EXIT(tDecodeU64(&decoder, &pInfo->walInDiskSize));
1,716✔
7929
  TAOS_CHECK_EXIT(tDecodeU64(&decoder, &pInfo->rawDataSize));
1,716✔
7930

7931
_exit:
858✔
7932
  tDecoderClear(&decoder);
858✔
7933
  return code;
858✔
7934
}
7935
int32_t blockDBUsageFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
429✔
7936
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
429✔
7937
  SDBBlockUsageInfo*   pData = GET_ROWCELL_INTERBUF(pResInfo);
429✔
7938

7939
  SColumnInfoData* pColInfo = taosArrayGet(pBlock->pDataBlock, 0);
429✔
7940
  if (NULL == pColInfo) {
429✔
7941
    return TSDB_CODE_OUT_OF_RANGE;
×
7942
  }
7943
  int32_t len = 0;
429✔
7944
  int32_t row = 0;
429✔
7945
  char    st[256] = {0};
429✔
7946

7947
  uint64_t totalDiskSize = pData->dataInDiskSize;
429✔
7948
  uint64_t rawDataSize = pData->rawDataSize;
429✔
7949
  double   compressRatio = 0;
429✔
7950
  if (rawDataSize != 0) {
429✔
7951
    compressRatio = totalDiskSize * 100 / (double)rawDataSize;
222✔
7952
    len = tsnprintf(varDataVal(st), sizeof(st) - VARSTR_HEADER_SIZE, "Compress_ratio=[%.2f%]", compressRatio);
222✔
7953
  } else {
7954
    len = tsnprintf(varDataVal(st), sizeof(st) - VARSTR_HEADER_SIZE, "Compress_ratio=[NULL]");
207✔
7955
  }
7956

7957
  varDataSetLen(st, len);
429✔
7958
  int32_t code = colDataSetVal(pColInfo, row++, st, false);
429✔
7959
  if (TSDB_CODE_SUCCESS != code) {
429✔
7960
    return code;
×
7961
  }
7962

7963
  len =
7964
      snprintf(varDataVal(st), sizeof(st) - VARSTR_HEADER_SIZE, "Disk_occupied=[%" PRId64 "k]", pData->dataInDiskSize);
429✔
7965
  varDataSetLen(st, len);
429✔
7966
  code = colDataSetVal(pColInfo, row++, st, false);
429✔
7967
  if (TSDB_CODE_SUCCESS != code) {
429✔
7968
    return code;
×
7969
  }
7970
  return code;
429✔
7971
}
7972

7973
bool getDerivativeFuncEnv(struct SFunctionNode* pFunc, SFuncExecEnv* pEnv) {
249,167✔
7974
  pEnv->calcMemSize = sizeof(SDerivInfo);
249,167✔
7975
  return true;
249,167✔
7976
}
7977

7978
int32_t derivativeFuncSetup(SqlFunctionCtx* pCtx, SResultRowEntryInfo* pResInfo) {
963,494✔
7979
  if (pResInfo->initialized) {
963,494✔
7980
    return TSDB_CODE_SUCCESS;
605,872✔
7981
  }
7982
  if (TSDB_CODE_SUCCESS != functionSetup(pCtx, pResInfo)) {
357,622✔
7983
    return TSDB_CODE_FUNC_SETUP_ERROR;
×
7984
  }
7985

7986
  SDerivInfo* pDerivInfo = GET_ROWCELL_INTERBUF(pResInfo);
357,622✔
7987

7988
  pDerivInfo->ignoreNegative = pCtx->param[2].param.i;
357,622✔
7989
  pDerivInfo->prevTs = -1;
357,622✔
7990
  pDerivInfo->tsWindow = pCtx->param[1].param.i;
357,622✔
7991
  pDerivInfo->valueSet = false;
357,622✔
7992
  return TSDB_CODE_SUCCESS;
357,622✔
7993
}
7994

7995
int32_t derivativeFunction(SqlFunctionCtx* pCtx) { return TSDB_CODE_SUCCESS; }
641,865✔
7996

7997
static int32_t DoDerivativeFunction(SqlFunctionCtx* pCtx) {
641,865✔
7998
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
641,865✔
7999
  SDerivInfo*          pDerivInfo = GET_ROWCELL_INTERBUF(pResInfo);
641,865✔
8000

8001
  SInputColumnInfoData* pInput = &pCtx->input;
641,865✔
8002
  SColumnInfoData*      pInputCol = pInput->pData[0];
641,865✔
8003

8004
  int32_t          numOfElems = 0;
641,865✔
8005
  SColumnInfoData* pOutput = (SColumnInfoData*)pCtx->pOutput;
641,865✔
8006
  SColumnInfoData* pTsOutput = pCtx->pTsOutput;
641,865✔
8007
  int32_t          code = TSDB_CODE_SUCCESS;
641,865✔
8008

8009
  funcInputUpdate(pCtx);
641,865✔
8010

8011
  double v = 0;
641,865✔
8012
  if (pCtx->order == TSDB_ORDER_ASC) {
641,865✔
8013
    SFuncInputRow row = {0};
553,148✔
8014
    bool          result = false;
553,148✔
8015
    while (1) {
139,683,408✔
8016
      code = funcInputGetNextRow(pCtx, &row, &result);
140,236,556✔
8017
      if (TSDB_CODE_SUCCESS != code) {
140,236,556✔
8018
        return code;
×
8019
      }
8020
      if (!result) {
140,236,556✔
8021
        break;
553,148✔
8022
      }
8023
      if (row.isDataNull) {
139,683,408✔
8024
        continue;
3,665,562✔
8025
      }
8026

8027
      char* d = row.pData;
136,017,846✔
8028
      GET_TYPED_DATA(v, double, pInputCol->info.type, d, typeGetTypeModFromColInfo(&pInputCol->info));
136,017,846✔
8029

8030
      int32_t pos = pCtx->offset + numOfElems;
136,017,846✔
8031
      if (!pDerivInfo->valueSet) {  // initial value is not set yet
136,017,846✔
8032
        pDerivInfo->valueSet = true;
263,751✔
8033
      } else {
8034
        if (row.ts == pDerivInfo->prevTs) {
135,754,095✔
8035
          return TSDB_CODE_FUNC_DUP_TIMESTAMP;
×
8036
        }
8037
        double r = ((v - pDerivInfo->prevValue) * pDerivInfo->tsWindow) / (row.ts - pDerivInfo->prevTs);
135,754,095✔
8038
        if (pDerivInfo->ignoreNegative && r < 0) {
135,754,095✔
8039
        } else {
8040
          if (isinf(r) || isnan(r)) {
124,344,869✔
8041
            colDataSetNULL(pOutput, pos);
×
8042
          } else {
8043
            code = colDataSetVal(pOutput, pos, (const char*)&r, false);
124,344,869✔
8044
            if (code != TSDB_CODE_SUCCESS) {
124,344,869✔
8045
              return code;
×
8046
            }
8047
          }
8048

8049
          if (pTsOutput != NULL) {
124,344,869✔
8050
            colDataSetInt64(pTsOutput, pos, &row.ts);
3,403,816✔
8051
          }
8052

8053
          // handle selectivity
8054
          if (pCtx->subsidiaries.num > 0) {
124,344,869✔
8055
            code = appendSelectivityCols(pCtx, row.block, row.rowIndex, pos);
2,130,034✔
8056
            if (code != TSDB_CODE_SUCCESS) {
2,130,034✔
8057
              return code;
×
8058
            }
8059
          }
8060

8061
          numOfElems++;
124,344,869✔
8062
        }
8063
      }
8064

8065
      pDerivInfo->prevValue = v;
136,017,846✔
8066
      pDerivInfo->prevTs = row.ts;
136,017,846✔
8067
    }
8068
  } else {
8069
    SFuncInputRow row = {0};
88,717✔
8070
    bool          result = false;
88,717✔
8071
    while (1) {
31,535,061✔
8072
      code = funcInputGetNextRow(pCtx, &row, &result);
31,623,778✔
8073
      if (TSDB_CODE_SUCCESS != code) {
31,623,778✔
8074
        return code;
×
8075
      }
8076
      if (!result) {
31,623,778✔
8077
        break;
88,717✔
8078
      }
8079
      if (row.isDataNull) {
31,535,061✔
8080
        continue;
4,672✔
8081
      }
8082

8083
      char* d = row.pData;
31,530,389✔
8084
      GET_TYPED_DATA(v, double, pInputCol->info.type, d, typeGetTypeModFromColInfo(&pInputCol->info));
31,530,389✔
8085

8086
      int32_t pos = pCtx->offset + numOfElems;
31,530,389✔
8087
      if (!pDerivInfo->valueSet) {  // initial value is not set yet
31,530,389✔
8088
        pDerivInfo->valueSet = true;
57,521✔
8089
      } else {
8090
        if (row.ts == pDerivInfo->prevTs) {
31,472,868✔
8091
          return TSDB_CODE_FUNC_DUP_TIMESTAMP;
×
8092
        }
8093
        double r = ((pDerivInfo->prevValue - v) * pDerivInfo->tsWindow) / (pDerivInfo->prevTs - row.ts);
31,472,868✔
8094
        if (pDerivInfo->ignoreNegative && r < 0) {
31,472,868✔
8095
        } else {
8096
          if (isinf(r) || isnan(r)) {
31,472,311✔
8097
            colDataSetNULL(pOutput, pos);
×
8098
          } else {
8099
            code = colDataSetVal(pOutput, pos, (const char*)&r, false);
31,472,311✔
8100
            if (code != TSDB_CODE_SUCCESS) {
31,472,311✔
8101
              return code;
×
8102
            }
8103
          }
8104

8105
          if (pTsOutput != NULL) {
31,472,311✔
8106
            colDataSetInt64(pTsOutput, pos, &pDerivInfo->prevTs);
31,468,944✔
8107
          }
8108

8109
          // handle selectivity
8110
          if (pCtx->subsidiaries.num > 0) {
31,472,311✔
8111
            code = appendSelectivityCols(pCtx, row.block, row.rowIndex, pos);
×
8112
            if (code != TSDB_CODE_SUCCESS) {
×
8113
              return code;
×
8114
            }
8115
          }
8116
          numOfElems++;
31,472,311✔
8117
        }
8118
      }
8119

8120
      pDerivInfo->prevValue = v;
31,530,389✔
8121
      pDerivInfo->prevTs = row.ts;
31,530,389✔
8122
    }
8123
  }
8124

8125
  pResInfo->numOfRes = numOfElems;
641,865✔
8126

8127
  return TSDB_CODE_SUCCESS;
641,865✔
8128
}
8129

8130
int32_t derivativeFunctionByRow(SArray* pCtxArray) {
641,865✔
8131
  for (int32_t i = 0; i < taosArrayGetSize(pCtxArray); ++i) {
1,283,730✔
8132
    SqlFunctionCtx* pCtx = *(SqlFunctionCtx**)taosArrayGet(pCtxArray, i);
641,865✔
8133
    int32_t         code = DoDerivativeFunction(pCtx);
641,865✔
8134
    if (code != TSDB_CODE_SUCCESS) {
641,865✔
8135
      return code;
×
8136
    }
8137
  }
8138
  return TSDB_CODE_SUCCESS;
641,865✔
8139
}
8140

8141
int32_t getIrateInfoSize(int32_t pkBytes) { return (int32_t)sizeof(SRateInfo) + 2 * pkBytes; }
279,013✔
8142

8143
bool getIrateFuncEnv(struct SFunctionNode* pFunc, SFuncExecEnv* pEnv) {
232,950✔
8144
  int32_t pkBytes = (pFunc->hasPk) ? pFunc->pkBytes : 0;
232,950✔
8145
  pEnv->calcMemSize = getIrateInfoSize(pkBytes);
232,950✔
8146
  return true;
232,950✔
8147
}
8148

8149
int32_t irateFuncSetup(SqlFunctionCtx* pCtx, SResultRowEntryInfo* pResInfo) {
1,854,338✔
8150
  if (pResInfo->initialized) {
1,854,338✔
8151
    return TSDB_CODE_SUCCESS;
×
8152
  }
8153
  if (TSDB_CODE_SUCCESS != functionSetup(pCtx, pResInfo)) {
1,854,338✔
8154
    return TSDB_CODE_FUNC_SETUP_ERROR;
×
8155
  }
8156

8157
  SRateInfo* pInfo = GET_ROWCELL_INTERBUF(pResInfo);
1,854,338✔
8158

8159
  pInfo->firstKey = INT64_MIN;
1,854,338✔
8160
  pInfo->lastKey = INT64_MIN;
1,854,338✔
8161
  pInfo->firstValue = (double)INT64_MIN;
1,854,338✔
8162
  pInfo->lastValue = (double)INT64_MIN;
1,854,338✔
8163

8164
  pInfo->hasResult = 0;
1,854,338✔
8165
  return TSDB_CODE_SUCCESS;
1,854,338✔
8166
}
8167

8168
static void doSaveRateInfo(SRateInfo* pRateInfo, bool isFirst, int64_t ts, char* pk, double v) {
328,869,707✔
8169
  if (isFirst) {
328,869,707✔
8170
    pRateInfo->firstValue = v;
163,837,993✔
8171
    pRateInfo->firstKey = ts;
163,837,993✔
8172
    if (pRateInfo->firstPk) {
163,837,993✔
8173
      int32_t pkBytes;
8174
      if (IS_VAR_DATA_TYPE(pRateInfo->pkType)) {
26,215✔
8175
        pkBytes = calcStrBytesByType(pRateInfo->pkType, pk);
5,992✔
8176
      } else {
8177
        pkBytes = pRateInfo->pkBytes;
20,223✔
8178
      }
8179
      (void)memcpy(pRateInfo->firstPk, pk, pkBytes);
26,215✔
8180
    }
8181
  } else {
8182
    pRateInfo->lastValue = v;
165,031,714✔
8183
    pRateInfo->lastKey = ts;
165,031,714✔
8184
    if (pRateInfo->lastPk) {
165,031,714✔
8185
      int32_t pkBytes;
8186
      if (IS_VAR_DATA_TYPE(pRateInfo->pkType)) {
38,948✔
8187
        pkBytes = calcStrBytesByType(pRateInfo->pkType, pk);
8,988✔
8188
      } else {
8189
        pkBytes = pRateInfo->pkBytes;
29,960✔
8190
      }
8191
      (void)memcpy(pRateInfo->lastPk, pk, pkBytes);
38,948✔
8192
    }
8193
  }
8194
}
328,869,707✔
8195

8196
static void initializeRateInfo(SqlFunctionCtx* pCtx, SRateInfo* pRateInfo, bool isMerge) {
2,015,104✔
8197
  if (pCtx->hasPrimaryKey) {
2,015,104✔
8198
    if (!isMerge) {
14,231✔
8199
      pRateInfo->pkType = pCtx->input.pPrimaryKey->info.type;
12,733✔
8200
      pRateInfo->pkBytes = pCtx->input.pPrimaryKey->info.bytes;
12,733✔
8201
      pRateInfo->firstPk = pRateInfo->pkData;
12,733✔
8202
      pRateInfo->lastPk = pRateInfo->pkData + pRateInfo->pkBytes;
12,733✔
8203
    } else {
8204
      pRateInfo->firstPk = pRateInfo->pkData;
1,498✔
8205
      pRateInfo->lastPk = pRateInfo->pkData + pRateInfo->pkBytes;
1,498✔
8206
    }
8207
  } else {
8208
    pRateInfo->firstPk = NULL;
2,000,873✔
8209
    pRateInfo->lastPk = NULL;
2,000,873✔
8210
  }
8211
}
2,015,104✔
8212

8213
int32_t irateFunction(SqlFunctionCtx* pCtx) {
1,947,422✔
8214
  int32_t              code = TSDB_CODE_SUCCESS;
1,947,422✔
8215
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
1,947,422✔
8216
  SRateInfo*           pRateInfo = GET_ROWCELL_INTERBUF(pResInfo);
1,947,422✔
8217

8218
  SInputColumnInfoData* pInput = &pCtx->input;
1,947,422✔
8219
  SColumnInfoData*      pInputCol = pInput->pData[0];
1,947,422✔
8220

8221
  SColumnInfoData* pOutput = (SColumnInfoData*)pCtx->pOutput;
1,947,422✔
8222

8223
  funcInputUpdate(pCtx);
1,947,422✔
8224

8225
  initializeRateInfo(pCtx, pRateInfo, false);
1,947,422✔
8226

8227
  int32_t       numOfElems = 0;
1,947,422✔
8228
  int32_t       type = pInputCol->info.type;
1,947,422✔
8229
  SFuncInputRow row = {0};
1,947,422✔
8230
  bool          result = false;
1,947,422✔
8231
  while (1) {
217,521,792✔
8232
    code = funcInputGetNextRow(pCtx, &row, &result);
219,469,214✔
8233
    if (TSDB_CODE_SUCCESS != code) {
219,469,214✔
8234
      return code;
×
8235
    }
8236
    if (!result) {
219,469,214✔
8237
      break;
1,947,422✔
8238
    }
8239
    if (row.isDataNull) {
217,521,792✔
8240
      continue;
8,174,051✔
8241
    }
8242

8243
    char*  data = row.pData;
209,347,741✔
8244
    double v = 0;
209,347,741✔
8245
    GET_TYPED_DATA(v, double, type, data, typeGetTypeModFromColInfo(&pInputCol->info));
209,347,741✔
8246

8247
    if (INT64_MIN == pRateInfo->lastKey) {
209,347,741✔
8248
      doSaveRateInfo(pRateInfo, false, row.ts, row.pPk, v);
1,197,963✔
8249
      pRateInfo->hasResult = 1;
1,197,963✔
8250
      continue;
1,197,963✔
8251
    }
8252

8253
    if (row.ts > pRateInfo->lastKey) {
208,149,778✔
8254
      if ((INT64_MIN == pRateInfo->firstKey) || pRateInfo->lastKey > pRateInfo->firstKey) {
163,810,200✔
8255
        doSaveRateInfo(pRateInfo, true, pRateInfo->lastKey, pRateInfo->lastPk, pRateInfo->lastValue);
163,810,200✔
8256
      }
8257
      doSaveRateInfo(pRateInfo, false, row.ts, row.pPk, v);
163,810,200✔
8258
      continue;
163,810,200✔
8259
    } else if (row.ts == pRateInfo->lastKey) {
44,339,578✔
8260
      return TSDB_CODE_FUNC_DUP_TIMESTAMP;
×
8261
    }
8262

8263
    if ((INT64_MIN == pRateInfo->firstKey) || row.ts > pRateInfo->firstKey) {
44,339,578✔
8264
      doSaveRateInfo(pRateInfo, true, row.ts, row.pPk, v);
2,282✔
8265
    } else if (row.ts == pRateInfo->firstKey) {
44,337,296✔
8266
      return TSDB_CODE_FUNC_DUP_TIMESTAMP;
×
8267
    }
8268
  }
8269

8270
  numOfElems++;
1,947,422✔
8271

8272
  SET_VAL(pResInfo, numOfElems, 1);
1,947,422✔
8273
  return TSDB_CODE_SUCCESS;
1,947,422✔
8274
}
8275

8276
static double doCalcRate(const SRateInfo* pRateInfo, double tickPerSec) {
1,819,535✔
8277
  if ((INT64_MIN == pRateInfo->lastKey) || (INT64_MIN == pRateInfo->firstKey) ||
1,819,535✔
8278
      (pRateInfo->firstKey >= pRateInfo->lastKey)) {
162,335✔
8279
    return 0.0;
1,657,200✔
8280
  }
8281

8282
  double diff = 0;
162,335✔
8283
  // If the previous value of the last is greater than the last value, only keep the last point instead of the delta
8284
  // value between two values.
8285
  diff = pRateInfo->lastValue;
162,335✔
8286
  if (diff >= pRateInfo->firstValue) {
162,335✔
8287
    diff -= pRateInfo->firstValue;
116,260✔
8288
  }
8289

8290
  int64_t duration = pRateInfo->lastKey - pRateInfo->firstKey;
162,335✔
8291
  if (duration == 0) {
162,335✔
8292
    return 0;
×
8293
  }
8294

8295
  return (duration > 0) ? ((double)diff) / (duration / tickPerSec) : 0.0;
162,335✔
8296
}
8297

8298
static void irateTransferInfoImpl(TSKEY inputKey, SRateInfo* pInput, SRateInfo* pOutput, bool isFirstKey) {
27,940✔
8299
  if (inputKey > pOutput->lastKey) {
27,940✔
8300
    doSaveRateInfo(pOutput, true, pOutput->lastKey, pOutput->lastPk, pOutput->lastValue);
5,880✔
8301
    if (isFirstKey) {
5,880✔
8302
      doSaveRateInfo(pOutput, false, pInput->firstKey, pInput->firstPk, pInput->firstValue);
1,960✔
8303
    } else {
8304
      doSaveRateInfo(pOutput, false, pInput->lastKey, pInput->lastPk, pInput->lastValue);
3,920✔
8305
    }
8306
  } else if ((inputKey < pOutput->lastKey) && (inputKey > pOutput->firstKey)) {
22,060✔
8307
    if (isFirstKey) {
1,960✔
8308
      doSaveRateInfo(pOutput, true, pInput->firstKey, pInput->firstPk, pInput->firstValue);
980✔
8309
    } else {
8310
      doSaveRateInfo(pOutput, true, pInput->lastKey, pInput->lastPk, pInput->lastValue);
980✔
8311
    }
8312
  } else {
8313
    // inputKey < pOutput->firstKey
8314
  }
8315
}
27,940✔
8316

8317
static void irateCopyInfo(SRateInfo* pInput, SRateInfo* pOutput) {
17,671✔
8318
  doSaveRateInfo(pOutput, true, pInput->firstKey, pInput->firstPk, pInput->firstValue);
17,671✔
8319
  doSaveRateInfo(pOutput, false, pInput->lastKey, pInput->lastPk, pInput->lastValue);
17,671✔
8320
}
17,671✔
8321

8322
static int32_t irateTransferInfo(SRateInfo* pInput, SRateInfo* pOutput) {
31,641✔
8323
  if ((pInput->firstKey != INT64_MIN &&
31,641✔
8324
       (pInput->firstKey == pOutput->firstKey || pInput->firstKey == pOutput->lastKey)) ||
28,689✔
8325
      (pInput->lastKey != INT64_MIN && (pInput->lastKey == pOutput->firstKey || pInput->lastKey == pOutput->lastKey))) {
31,641✔
8326
    return TSDB_CODE_FUNC_DUP_TIMESTAMP;
×
8327
  }
8328

8329
  if (pOutput->hasResult == 0) {
31,641✔
8330
    irateCopyInfo(pInput, pOutput);
17,671✔
8331
    pOutput->hasResult = pInput->hasResult;
17,671✔
8332
    return TSDB_CODE_SUCCESS;
17,671✔
8333
  }
8334

8335
  if (pInput->firstKey != INT64_MIN) {
13,970✔
8336
    irateTransferInfoImpl(pInput->firstKey, pInput, pOutput, true);
13,970✔
8337
  }
8338

8339
  if (pInput->lastKey != INT64_MIN) {
13,970✔
8340
    irateTransferInfoImpl(pInput->lastKey, pInput, pOutput, false);
13,970✔
8341
  }
8342

8343
  pOutput->hasResult = pInput->hasResult;
13,970✔
8344
  return TSDB_CODE_SUCCESS;
13,970✔
8345
}
8346

8347
int32_t irateFunctionMerge(SqlFunctionCtx* pCtx) {
33,841✔
8348
  SInputColumnInfoData* pInput = &pCtx->input;
33,841✔
8349
  SColumnInfoData*      pCol = pInput->pData[0];
33,841✔
8350
  if (pCol->info.type != TSDB_DATA_TYPE_BINARY) {
33,841✔
8351
    return TSDB_CODE_FUNC_FUNTION_PARA_TYPE;
×
8352
  }
8353

8354
  SRateInfo* pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
33,841✔
8355
  initializeRateInfo(pCtx, pInfo, true);
33,841✔
8356

8357
  int32_t start = pInput->startRowIndex;
33,841✔
8358
  for (int32_t i = start; i < start + pInput->numOfRows; ++i) {
67,682✔
8359
    char*      data = colDataGetData(pCol, i);
33,841✔
8360
    SRateInfo* pInputInfo = (SRateInfo*)varDataVal(data);
33,841✔
8361
    initializeRateInfo(pCtx, pInfo, true);
33,841✔
8362
    if (pInputInfo->hasResult) {
33,841✔
8363
      int32_t code = irateTransferInfo(pInputInfo, pInfo);
31,641✔
8364
      if (code != TSDB_CODE_SUCCESS) {
31,641✔
8365
        return code;
×
8366
      }
8367
    }
8368
  }
8369

8370
  if (pInfo->hasResult) {
33,841✔
8371
    GET_RES_INFO(pCtx)->numOfRes = 1;
31,641✔
8372
  }
8373

8374
  return TSDB_CODE_SUCCESS;
33,841✔
8375
}
8376

8377
int32_t iratePartialFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
33,841✔
8378
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
33,841✔
8379
  SRateInfo*           pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
33,841✔
8380
  int32_t              resultBytes = getIrateInfoSize(pInfo->pkBytes);
33,841✔
8381
  char*                res = taosMemoryCalloc(resultBytes + VARSTR_HEADER_SIZE, sizeof(char));
33,841✔
8382

8383
  if (NULL == res) {
33,841✔
8384
    return terrno;
×
8385
  }
8386
  (void)memcpy(varDataVal(res), pInfo, resultBytes);
33,841✔
8387
  varDataSetLen(res, resultBytes);
33,841✔
8388

8389
  int32_t          slotId = pCtx->pExpr->base.resSchema.slotId;
33,841✔
8390
  SColumnInfoData* pCol = taosArrayGet(pBlock->pDataBlock, slotId);
33,841✔
8391
  if (NULL == pCol) {
33,841✔
8392
    taosMemoryFree(res);
×
8393
    return TSDB_CODE_OUT_OF_RANGE;
×
8394
  }
8395

8396
  int32_t code = colDataSetVal(pCol, pBlock->info.rows, res, false);
33,841✔
8397

8398
  taosMemoryFree(res);
33,841✔
8399
  return code;
33,841✔
8400
}
8401

8402
int32_t irateFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
1,819,535✔
8403
  int32_t          slotId = pCtx->pExpr->base.resSchema.slotId;
1,819,535✔
8404
  SColumnInfoData* pCol = taosArrayGet(pBlock->pDataBlock, slotId);
1,819,535✔
8405
  if (NULL == pCol) {
1,819,535✔
8406
    return TSDB_CODE_OUT_OF_RANGE;
×
8407
  }
8408

8409
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
1,819,535✔
8410
  pResInfo->isNullRes = (pResInfo->numOfRes == 0) ? 1 : 0;
1,819,535✔
8411

8412
  SRateInfo* pInfo = GET_ROWCELL_INTERBUF(pResInfo);
1,819,535✔
8413
  double     result = doCalcRate(pInfo, (double)TSDB_TICK_PER_SECOND(pCtx->param[1].param.i));
1,819,535✔
8414
  int32_t    code = colDataSetVal(pCol, pBlock->info.rows, (const char*)&result, pResInfo->isNullRes);
1,819,535✔
8415

8416
  return code;
1,819,535✔
8417
}
8418

8419
int32_t groupConstValueFunction(SqlFunctionCtx* pCtx) {
2,147,483,647✔
8420
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
2,147,483,647✔
8421
  SGroupKeyInfo*       pInfo = GET_ROWCELL_INTERBUF(pResInfo);
2,147,483,647✔
8422
  bool                 isWindow = pCtx->hasWindowOrGroup && pCtx->hasWindow;
2,147,483,647✔
8423

8424
  if (pInfo->hasResult && (!isWindow || !pInfo->isNull)) {
2,147,483,647✔
8425
    // If already has result for 'group by' or
8426
    // has non-null result for 'window', we can skip left data blocks.
8427
    goto _group_value_over;
2,147,483,647✔
8428
  }
8429

8430
  int32_t               valueRowIndex = -1;
2,147,483,647✔
8431
  SInputColumnInfoData* pInput = &pCtx->input;
2,147,483,647✔
8432
  SColumnInfoData*      pInputCol = pInput->pData[0];
2,147,483,647✔
8433

8434
  // try to find a non-null value
8435
  if (NULL != pInputCol->pData) {
2,147,483,647✔
8436
    if (isWindow) {
2,147,483,647✔
8437
      // for 'window', non-null value can appear at any row of any data block
8438
      int64_t startIndex = pInput->startRowIndex;
2,147,483,647✔
8439
      int64_t endIndex = pInput->startRowIndex + pInput->numOfRows - 1;
2,147,483,647✔
8440
      for (int64_t i = startIndex; i <= endIndex; ++i) {
2,147,483,647✔
8441
        if (!colDataIsNull_s(pInputCol, i)) {
2,147,483,647✔
8442
          valueRowIndex = i;
2,147,483,647✔
8443
          break;
2,147,483,647✔
8444
        }
8445
      }
8446
    } else {
8447
      // for 'group by', just take the first row
8448
      if (!colDataIsNull_s(pInputCol, pInput->startRowIndex)) {
451,858,231✔
8449
        valueRowIndex = pInput->startRowIndex;
223,555,166✔
8450
      }
8451
    }
8452
  }
8453

8454
  if (valueRowIndex != -1) {
2,147,483,647✔
8455
    // found a non-null value
8456
    char* data = colDataGetData(pInputCol, valueRowIndex);
2,147,483,647✔
8457
    if (IS_VAR_DATA_TYPE(pInputCol->info.type)) {
2,147,483,647✔
8458
      int32_t bytes = calcStrBytesByType(pInputCol->info.type, data);
2,147,483,647✔
8459
      (void)memcpy(pInfo->data, data, bytes);
2,147,483,647✔
8460
    } else {
8461
      (void)memcpy(pInfo->data, data, pInputCol->info.bytes);
2,147,483,647✔
8462
    }
8463
    pInfo->isNull = false;
2,147,483,647✔
8464
  } else {
8465
    // all values are null or first value is null for group by
8466
    pInfo->isNull = true;
1,453,521,131✔
8467
  }
8468
  pInfo->hasResult = true;
2,147,483,647✔
8469

8470
_group_value_over:
2,147,483,647✔
8471
  SET_VAL(pResInfo, 1, 1);
2,147,483,647✔
8472
  return TSDB_CODE_SUCCESS;
2,147,483,647✔
8473
}
8474

8475
int32_t groupKeyFunction(SqlFunctionCtx* pCtx) { return groupConstValueFunction(pCtx); }
2,147,483,647✔
8476

8477
int32_t groupConstValueFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
2,147,483,647✔
8478
  int32_t          slotId = pCtx->pExpr->base.resSchema.slotId;
2,147,483,647✔
8479
  int32_t          code = TSDB_CODE_SUCCESS;
2,147,483,647✔
8480
  SColumnInfoData* pCol = taosArrayGet(pBlock->pDataBlock, slotId);
2,147,483,647✔
8481
  if (NULL == pCol) {
2,147,483,647✔
8482
    return TSDB_CODE_OUT_OF_RANGE;
×
8483
  }
8484

8485
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
2,147,483,647✔
8486

8487
  SGroupKeyInfo* pInfo = GET_ROWCELL_INTERBUF(pResInfo);
2,147,483,647✔
8488

8489
  if (pInfo->hasResult) {
2,147,483,647✔
8490
    int32_t currentRow = pBlock->info.rows;
2,147,483,647✔
8491
    for (; currentRow < pBlock->info.rows + pResInfo->numOfRes; ++currentRow) {
2,147,483,647✔
8492
      code = colDataSetVal(pCol, currentRow, pInfo->data, pInfo->isNull ? true : false);
2,147,483,647✔
8493
      if (TSDB_CODE_SUCCESS != code) {
2,147,483,647✔
8494
        return code;
×
8495
      }
8496
    }
8497
  } else {
8498
    pResInfo->numOfRes = 0;
×
8499
  }
8500

8501
  return code;
2,147,483,647✔
8502
}
8503

8504
int32_t groupKeyFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) { return groupConstValueFinalize(pCtx, pBlock); }
2,147,483,647✔
8505

8506
int32_t groupKeyCombine(SqlFunctionCtx* pDestCtx, SqlFunctionCtx* pSourceCtx) {
×
8507
  SResultRowEntryInfo* pDResInfo = GET_RES_INFO(pDestCtx);
×
8508
  SGroupKeyInfo*       pDBuf = GET_ROWCELL_INTERBUF(pDResInfo);
×
8509

8510
  SResultRowEntryInfo* pSResInfo = GET_RES_INFO(pSourceCtx);
×
8511
  SGroupKeyInfo*       pSBuf = GET_ROWCELL_INTERBUF(pSResInfo);
×
8512

8513
  // escape rest of data blocks to avoid first entry to be overwritten.
8514
  if (pDBuf->hasResult) {
×
8515
    goto _group_key_over;
×
8516
  }
8517

8518
  if (pSBuf->isNull) {
×
8519
    pDBuf->isNull = true;
×
8520
    pDBuf->hasResult = true;
×
8521
    goto _group_key_over;
×
8522
  }
8523

8524
  if (IS_VAR_DATA_TYPE(pSourceCtx->resDataInfo.type)) {
×
8525
    int32_t bytes = calcStrBytesByType(pSourceCtx->resDataInfo.type, pSBuf->data);
×
8526
    (void)memcpy(pDBuf->data, pSBuf->data, bytes);
×
8527
  } else {
8528
    (void)memcpy(pDBuf->data, pSBuf->data, pSourceCtx->resDataInfo.bytes);
×
8529
  }
8530

8531
  pDBuf->hasResult = true;
×
8532

8533
_group_key_over:
×
8534

8535
  SET_VAL(pDResInfo, 1, 1);
×
8536
  return TSDB_CODE_SUCCESS;
×
8537
}
8538

8539
int32_t cachedLastRowFunction(SqlFunctionCtx* pCtx) {
663,564✔
8540
  int32_t numOfElems = 0;
663,564✔
8541

8542
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
663,564✔
8543
  SFirstLastRes*       pInfo = GET_ROWCELL_INTERBUF(pResInfo);
663,564✔
8544

8545
  SInputColumnInfoData* pInput = &pCtx->input;
663,564✔
8546
  SColumnInfoData*      pInputCol = pInput->pData[0];
663,564✔
8547

8548
  int32_t bytes = pInputCol->info.bytes;
663,564✔
8549
  pInfo->bytes = bytes;
663,564✔
8550

8551
  SColumnInfoData* pkCol = pInput->pPrimaryKey;
662,846✔
8552
  pInfo->pkType = -1;
663,564✔
8553
  __compar_fn_t pkCompareFn = NULL;
663,564✔
8554
  if (pCtx->hasPrimaryKey) {
663,564✔
8555
    pInfo->pkType = pkCol->info.type;
220,122✔
8556
    pInfo->pkBytes = pkCol->info.bytes;
220,122✔
8557
    pkCompareFn = getKeyComparFunc(pInfo->pkType, TSDB_ORDER_DESC);
220,122✔
8558
  }
8559

8560
  // data is guaranteed to be in descending order
8561
  for (int32_t i = pInput->numOfRows + pInput->startRowIndex - 1; i >= pInput->startRowIndex; --i) {
1,391,979✔
8562
    numOfElems++;
729,133✔
8563

8564
    bool  isNull = colDataIsNull(pInputCol, pInput->numOfRows, i, NULL);
729,133✔
8565
    char* data = isNull ? NULL : colDataGetData(pInputCol, i);
729,133✔
8566

8567
    TSKEY cts = getRowPTs(pInput->pPTS, i);
728,415✔
8568
    if (pResInfo->numOfRes == 0 || pInfo->ts < cts) {
729,133✔
8569
      int32_t code = doSaveLastrow(pCtx, data, i, cts, pInfo);
569,581✔
8570
      if (code != TSDB_CODE_SUCCESS) {
570,299✔
8571
        return code;
×
8572
      }
8573
      pResInfo->numOfRes = 1;
570,299✔
8574
    }
8575
  }
8576

8577
  SET_VAL(pResInfo, numOfElems, 1);
663,564✔
8578
  return TSDB_CODE_SUCCESS;
663,564✔
8579
}
8580

8581
bool getCorrFuncEnv(SFunctionNode* pFunc, SFuncExecEnv* pEnv) {
×
8582
  pEnv->calcMemSize = sizeof(SCorrRes);
×
8583
  return true;
×
8584
}
8585

8586
int32_t corrFuncSetup(SqlFunctionCtx* pCtx, SResultRowEntryInfo* pResultInfo) {
×
8587
  if (pResultInfo->initialized) {
×
8588
    return TSDB_CODE_SUCCESS;
×
8589
  }
8590
  if (TSDB_CODE_SUCCESS != functionSetup(pCtx, pResultInfo)) {
×
8591
    return TSDB_CODE_FUNC_SETUP_ERROR;
×
8592
  }
8593

8594
  SCorrRes* pRes = GET_ROWCELL_INTERBUF(pResultInfo);
×
8595
  (void)memset(pRes, 0, sizeof(SCorrRes));
×
8596
  return TSDB_CODE_SUCCESS;
×
8597
}
8598

8599
int32_t corrFunction(SqlFunctionCtx* pCtx) {
×
8600
  int32_t               numOfElem = 0;
×
8601
  SInputColumnInfoData* pInput = &pCtx->input;
×
8602
  int32_t               xType = pInput->pData[0]->info.type;
×
8603
  int32_t               yType = pInput->pData[1]->info.type;
×
8604
  SCorrRes*             pCorrRes = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
×
8605

8606
  // computing based on the true data block
8607
  SColumnInfoData* pLeft = pInput->pData[0];   // left
×
8608
  SColumnInfoData* pRight = pInput->pData[1];  // right
×
8609

8610
  int32_t leftMod = typeGetTypeModFromColInfo(&pLeft->info);
×
8611
  int32_t rightMod = typeGetTypeModFromColInfo(&pRight->info);
×
8612
  int32_t start = pInput->startRowIndex;
×
8613
  int32_t numOfRows = pInput->numOfRows;
×
8614

8615
  if (IS_NULL_TYPE(xType) || IS_NULL_TYPE(yType)) {
×
8616
    numOfElem = 0;
×
8617
    goto _over;
×
8618
  }
8619

8620
  for (int32_t i = 0; i < numOfRows; ++i) {
×
8621
    double pInputX = 0, pInputY = 0;
×
8622

8623
    if (colDataIsNull_f(pLeft, i) || colDataIsNull_f(pRight, i)) {
×
8624
      continue;
×
8625
    }
8626

8627
    char* pXVal = colDataGetData(pLeft, i);
×
8628
    char* pYVal = colDataGetData(pRight, i);
×
8629

8630
    GET_TYPED_DATA(pInputX, double, xType, pXVal, leftMod);
×
8631
    GET_TYPED_DATA(pInputY, double, yType, pYVal, rightMod);
×
8632

8633
    pCorrRes->sumLeft += pInputX;
×
8634
    pCorrRes->sumRight += pInputY;
×
8635

8636
    pCorrRes->quadLeft += pInputX * pInputX;
×
8637
    pCorrRes->quadRight += pInputY * pInputY;
×
8638

8639
    pCorrRes->productVal += pInputX * pInputY;
×
8640

8641
    pCorrRes->count += 1;
×
8642
    numOfElem += 1;
×
8643
  }
8644

8645
_over:
×
8646
  // data in the check operation are all null, not output
8647
  SET_VAL(GET_RES_INFO(pCtx), numOfElem, 1);
×
8648
  return TSDB_CODE_SUCCESS;
×
8649
}
8650

8651
int32_t corrFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
×
8652
  SInputColumnInfoData* pInput = &pCtx->input;
×
8653
  SCorrRes*             pRes = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
×
8654
  double                avg;
8655

8656
  if (pRes->count == 0) {
×
8657
    GET_RES_INFO(pCtx)->numOfRes = 0;
×
8658
    return functionFinalize(pCtx, pBlock);
×
8659
  }
8660

8661
  /**
8662
    numerator = sum_xy - (sum_x * sum_y) / n
8663
    denominator_x = math.sqrt(sum_x2 - (sum_x**2) / n)
8664
    denominator_y = math.sqrt(sum_y2 - (sum_y**2) / n)
8665

8666
    if denominator_x == 0 or denominator_y == 0:
8667
        return 0.0
8668
    res = numerator / (denominator_x * denominator_y)
8669
  */
8670

8671
  if (pRes->count == 1) {
×
8672
    pRes->result = 0.0;
×
8673
  } else {
8674
    double numerator = pRes->productVal - (pRes->sumLeft * pRes->sumRight) / pRes->count;
×
8675
    double dnmX = sqrt(pRes->quadLeft - pRes->sumLeft * pRes->sumLeft / pRes->count);
×
8676
    double dnmY = sqrt(pRes->quadRight - pRes->sumRight * pRes->sumRight / pRes->count);
×
8677

8678
    if (DBL_EQUAL(dnmX, 0.0) || DBL_EQUAL(dnmY, 0.0)) {
×
8679
      pRes->result = 0.0;
×
8680
    } else {
8681
      pRes->result = numerator / (dnmX * dnmY);
×
8682

8683
      if (pRes->result > 1 || pRes->result < -1) {
×
8684
        qError("invalid corr results, %.4f, numerator:%.4f, dnmX:%.4f, dnmY:%.4f", pRes->result, numerator, dnmX, dnmY);
×
8685
        if (pRes->result > 1) {
×
8686
          pRes->result = 1;
×
8687
        } else if (pRes->result < -1) {
×
8688
          pRes->result = -1;
×
8689
        }
8690
      }
8691
    }
8692
  }
8693

8694
  return functionFinalize(pCtx, pBlock);
×
8695
}
8696

8697
int32_t getCorrInfoSize() { return sizeof(SCorrRes); }
×
8698

8699
int32_t corrPartialFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
×
8700
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
×
8701
  SStdRes*             pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
×
8702
  int32_t              resultBytes = getCorrInfoSize();
×
8703
  char*                res = taosMemoryCalloc(resultBytes + VARSTR_HEADER_SIZE, sizeof(char));
×
8704
  int32_t              slotId = pCtx->pExpr->base.resSchema.slotId;
×
8705
  int32_t              code = 0;
×
8706

8707
  if (NULL == res) {
×
8708
    return terrno;
×
8709
  }
8710

8711
  (void)memcpy(varDataVal(res), pInfo, resultBytes);
×
8712
  varDataSetLen(res, resultBytes);
×
8713

8714
  SColumnInfoData* pCol = taosArrayGet(pBlock->pDataBlock, slotId);
×
8715
  if (NULL == pCol) {
×
8716
    taosMemoryFree(res);
×
8717
    return TSDB_CODE_OUT_OF_RANGE;
×
8718
  }
8719

8720
  code = colDataSetVal(pCol, pBlock->info.rows, res, false);
×
8721

8722
  taosMemoryFree(res);
×
8723
  return code;
×
8724
}
8725

8726
int32_t corrFuncMerge(SqlFunctionCtx* pCtx) {
×
8727
  SInputColumnInfoData* pInput = &pCtx->input;
×
8728
  SColumnInfoData*      pCol = pInput->pData[0];
×
8729

8730
  if (IS_NULL_TYPE(pCol->info.type)) {
×
8731
    SET_VAL(GET_RES_INFO(pCtx), 0, 1);
×
8732
    return TSDB_CODE_SUCCESS;
×
8733
  }
8734

8735
  if (pCol->info.type != TSDB_DATA_TYPE_BINARY) {
×
8736
    return TSDB_CODE_FUNC_FUNTION_PARA_TYPE;
×
8737
  }
8738

8739
  SCorrRes* pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
×
8740

8741
  for (int32_t i = pInput->startRowIndex; i < pInput->startRowIndex + pInput->numOfRows; ++i) {
×
8742
    if (colDataIsNull_s(pCol, i)) {
×
8743
      continue;
×
8744
    }
8745

8746
    char*     data = colDataGetData(pCol, i);
×
8747
    SCorrRes* pInputInfo = (SCorrRes*)varDataVal(data);
×
8748

8749
    if (pInputInfo->count == 0) {
×
8750
      continue;
×
8751
    }
8752

8753
    // pOutput->type = pInput->type;
8754
    if (pInfo->count == 0) {
×
8755
      TAOS_MEMCPY(pInfo, pInputInfo, sizeof(SCorrRes));
×
8756
    } else if (pInfo->count > 0) {
×
8757
      pInfo->productVal += pInputInfo->productVal;
×
8758
      pInfo->quadLeft += pInputInfo->quadLeft;
×
8759
      pInfo->quadRight += pInputInfo->quadRight;
×
8760
      pInfo->sumLeft += pInputInfo->sumLeft;
×
8761
      pInfo->sumRight += pInputInfo->sumRight;
×
8762
      pInfo->count += pInputInfo->count;
×
8763
    }
8764
  }
8765

8766
  SET_VAL(GET_RES_INFO(pCtx), pInfo->count, 1);
×
8767
  return TSDB_CODE_SUCCESS;
×
8768
}
8769

8770
int32_t hasNullFunction(SqlFunctionCtx* pCtx) {
17,512,860✔
8771
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
17,512,860✔
8772
  bool* pRes = GET_ROWCELL_INTERBUF(pResInfo);
17,512,860✔
8773
  if (*pRes) {
17,512,860✔
8774
    return TSDB_CODE_SUCCESS;
×
8775
  }
8776

8777
  SInputColumnInfoData* pInput = &pCtx->input;
17,512,860✔
8778
  SColumnDataAgg*       pAgg = pInput->pColumnDataAgg[0];
17,512,860✔
8779
  SColumnInfoData* pCol = pInput->pData[0];
17,512,860✔
8780

8781
  if (pInput->numOfRows > 0) {
17,512,860✔
8782
    pResInfo->numOfRes = 1;
17,512,860✔
8783
  }
8784

8785
  if (IS_NULL_TYPE(pCol->info.type) && pInput->numOfRows > 0) {
17,512,860✔
8786
    *pRes = true;
×
8787
    return TSDB_CODE_SUCCESS;
×
8788
  }
8789

8790
  if (pInput->colDataSMAIsSet) {
17,512,860✔
8791
    if (pAgg->numOfNull > 0) {
×
8792
      *pRes = true;
×
8793
      return TSDB_CODE_SUCCESS;
×
8794
    }
8795

8796
    if (pInput->numOfRows <= INT16_MAX) {
×
8797
      return TSDB_CODE_SUCCESS;
×
8798
    }
8799
  }
8800

8801
  int32_t start = pInput->startRowIndex;
17,512,860✔
8802
  int32_t end = start + pInput->numOfRows;
17,512,860✔
8803

8804
  if (pCol->hasNull) {
17,512,860✔
8805
    for (int32_t i = start; i < end; ++i) {
41,692,787✔
8806
      if (colDataIsNull_s(pCol, i)) {
70,692,866✔
8807
        *pRes = true;
11,066,906✔
8808
        break;
11,066,906✔
8809
      }
8810
    }
8811
  }  
8812

8813
  return TSDB_CODE_SUCCESS;
17,512,860✔
8814
}
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