Coverage Report

Created: 2026-09-04 06:24

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/tdengine/source/libs/function/src/detail/tminmax.c
Line
Count
Source
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 "function.h"
18
#include "tcompare.h"
19
#include "tdatablock.h"
20
#include "tfunctionInt.h"
21
#include "tglobal.h"
22
#include "decimal.h"
23
24
#define __COMPARE_ACQUIRED_MAX(i, end, bm, _data, ctx, val, pos) \
25
0
  int32_t code = TSDB_CODE_SUCCESS;                              \
26
0
  for (; i < (end); ++i) {                                       \
27
0
    if (BMIsNull(bm, i)) {                                \
28
0
      continue;                                                  \
29
0
    }                                                            \
30
0
                                                                 \
31
0
    if ((val) < (_data)[i]) {                                    \
32
0
      (val) = (_data)[i];                                        \
33
0
      if ((ctx)->subsidiaries.num > 0) {                         \
34
0
        code = updateTupleData((ctx), i, (ctx)->pSrcBlock, pos); \
35
0
        if (TSDB_CODE_SUCCESS != code) {                         \
36
0
          return code;                                           \
37
0
        }                                                        \
38
0
      }                                                          \
39
0
    }                                                            \
40
0
  }
41
42
#define __COMPARE_ACQUIRED_MIN(i, end, bm, _data, ctx, val, pos) \
43
0
  int32_t code = TSDB_CODE_SUCCESS;                              \
44
0
  for (; i < (end); ++i) {                                       \
45
0
    if (BMIsNull(bm, i)) {                                \
46
0
      continue;                                                  \
47
0
    }                                                            \
48
0
                                                                 \
49
0
    if ((val) > (_data)[i]) {                                    \
50
0
      (val) = (_data)[i];                                        \
51
0
      if ((ctx)->subsidiaries.num > 0) {                         \
52
0
        code = updateTupleData((ctx), i, (ctx)->pSrcBlock, pos); \
53
0
        if (TSDB_CODE_SUCCESS != code) {                         \
54
0
          return code;                                           \
55
0
        }                                                        \
56
0
      }                                                          \
57
0
    }                                                            \
58
0
  }
59
60
#define __COMPARE_EXTRACT_MIN(start, end, val, _data) \
61
0
  for (int32_t i = (start); i < (end); ++i) {         \
62
0
    if ((val) > (_data)[i]) {                         \
63
0
      (val) = (_data)[i];                             \
64
0
    }                                                 \
65
0
  }
66
67
#define __COMPARE_EXTRACT_MAX(start, end, val, _data) \
68
0
  for (int32_t i = (start); i < (end); ++i) {         \
69
0
    if ((val) < (_data)[i]) {                         \
70
0
      (val) = (_data)[i];                             \
71
0
    }                                                 \
72
0
  }
73
74
#define GET_INVOKE_INTRINSIC_THRESHOLD(_bits, _bytes) ((_bits) / ((_bytes) << 3u))
75
76
0
static int32_t findFirstValPosition(const SColumnInfoData* pCol, int32_t start, int32_t numOfRows, bool isStr) {
77
0
  int32_t i = start;
78
79
0
  while (i < (start + numOfRows) && (isStr ? colDataIsNull_s(pCol, i) : colDataIsNull_f(pCol, i) == true)) {
80
0
    i += 1;
81
0
  }
82
83
0
  return i;
84
0
}
85
86
static void handleInt8Col(const void* data, int32_t start, int32_t numOfRows, SMinmaxResInfo* pBuf, bool isMinFunc,
87
0
                          bool signVal) {
88
0
  if (!pBuf->assign) {
89
0
    pBuf->v = ((const int8_t*)data)[start];
90
0
  }
91
92
0
  if (tsAVX2Supported && tsSIMDEnable && numOfRows * sizeof(int8_t) >= M256_BYTES) {
93
0
    int32_t code = i8VectorCmpAVX2(((char*)data) + start * sizeof(int8_t), numOfRows, isMinFunc, signVal, &pBuf->v);
94
0
    if (code == TSDB_CODE_SUCCESS) {
95
0
      pBuf->assign = true;
96
0
      return;
97
0
    }
98
0
  }
99
100
0
  if (signVal) {
101
0
    const int8_t* p = (const int8_t*)data;
102
0
    int8_t*       v = (int8_t*)&pBuf->v;
103
104
0
    if (isMinFunc) {
105
0
      __COMPARE_EXTRACT_MIN(start, start + numOfRows, *v, p);
106
0
    } else {
107
0
      __COMPARE_EXTRACT_MAX(start, start + numOfRows, *v, p);
108
0
    }
109
0
  } else {
110
0
    const uint8_t* p = (const uint8_t*)data;
111
0
    uint8_t*       v = (uint8_t*)&pBuf->v;
112
113
0
    if (isMinFunc) {
114
0
      __COMPARE_EXTRACT_MIN(start, start + numOfRows, *v, p);
115
0
    } else {
116
0
      __COMPARE_EXTRACT_MAX(start, start + numOfRows, *v, p);
117
0
    }
118
0
  }
119
120
0
  pBuf->assign = true;
121
0
}
122
123
static void handleInt16Col(const void* data, int32_t start, int32_t numOfRows, SMinmaxResInfo* pBuf, bool isMinFunc,
124
0
                           bool signVal) {
125
0
  if (!pBuf->assign) {
126
0
    pBuf->v = ((const int16_t*)data)[start];
127
0
  }
128
129
0
  if (tsAVX2Supported && tsSIMDEnable && numOfRows * sizeof(int16_t) >= M256_BYTES) {
130
0
    int32_t code = i16VectorCmpAVX2(((char*)data) + start * sizeof(int16_t), numOfRows, isMinFunc, signVal, &pBuf->v);
131
0
    if (code == TSDB_CODE_SUCCESS) {
132
0
      pBuf->assign = true;
133
0
      return;
134
0
    }
135
0
  }
136
137
0
  if (signVal) {
138
0
    const int16_t* p = (const int16_t*)data;
139
0
    int16_t*       v = (int16_t*)&pBuf->v;
140
141
0
    if (isMinFunc) {
142
0
      __COMPARE_EXTRACT_MIN(start, start + numOfRows, *v, p);
143
0
    } else {
144
0
      __COMPARE_EXTRACT_MAX(start, start + numOfRows, *v, p);
145
0
    }
146
0
  } else {
147
0
    const uint16_t* p = (const uint16_t*)data;
148
0
    uint16_t*       v = (uint16_t*)&pBuf->v;
149
150
0
    if (isMinFunc) {
151
0
      __COMPARE_EXTRACT_MIN(start, start + numOfRows, *v, p);
152
0
    } else {
153
0
      __COMPARE_EXTRACT_MAX(start, start + numOfRows, *v, p);
154
0
    }
155
0
  }
156
157
0
  pBuf->assign = true;
158
0
}
159
160
static void handleInt32Col(const void* data, int32_t start, int32_t numOfRows, SMinmaxResInfo* pBuf, bool isMinFunc,
161
0
                           bool signVal) {
162
0
  if (!pBuf->assign) {
163
0
    pBuf->v = ((const int32_t*)data)[start];
164
0
  }
165
166
0
  if (tsAVX2Supported && tsSIMDEnable && numOfRows * sizeof(int32_t) >= M256_BYTES) {
167
0
    int32_t code = i32VectorCmpAVX2(((char*)data) + start * sizeof(int32_t), numOfRows, isMinFunc, signVal, &pBuf->v);
168
0
    if (code == TSDB_CODE_SUCCESS) {
169
0
      pBuf->assign = true;
170
0
      return;
171
0
    }
172
0
  }
173
174
0
  if (signVal) {
175
0
    const int32_t* p = (const int32_t*)data;
176
0
    int32_t*       v = (int32_t*)&pBuf->v;
177
178
0
    if (isMinFunc) {
179
0
      __COMPARE_EXTRACT_MIN(start, start + numOfRows, *v, p);
180
0
    } else {
181
0
      __COMPARE_EXTRACT_MAX(start, start + numOfRows, *v, p);
182
0
    }
183
0
  } else {
184
0
    const uint32_t* p = (const uint32_t*)data;
185
0
    uint32_t*       v = (uint32_t*)&pBuf->v;
186
187
0
    if (isMinFunc) {
188
0
      __COMPARE_EXTRACT_MIN(start, start + numOfRows, *v, p);
189
0
    } else {
190
0
      __COMPARE_EXTRACT_MAX(start, start + numOfRows, *v, p);
191
0
    }
192
0
  }
193
194
0
  pBuf->assign = true;
195
0
}
196
197
static void handleInt64Col(const void* data, int32_t start, int32_t numOfRows, SMinmaxResInfo* pBuf, bool isMinFunc,
198
0
                           bool signVal) {
199
0
  if (!pBuf->assign) {
200
0
    pBuf->v = ((const int64_t*)data)[start];
201
0
  }
202
203
0
  if (signVal) {
204
0
    const int64_t* p = (const int64_t*)data;
205
0
    int64_t*       v = &pBuf->v;
206
207
0
    if (isMinFunc) {
208
0
      __COMPARE_EXTRACT_MIN(start, start + numOfRows, *v, p);
209
0
    } else {
210
0
      __COMPARE_EXTRACT_MAX(start, start + numOfRows, *v, p);
211
0
    }
212
0
  } else {
213
0
    const uint64_t* p = (const uint64_t*)data;
214
0
    uint64_t*       v = (uint64_t*)&pBuf->v;
215
216
0
    if (isMinFunc) {
217
0
      __COMPARE_EXTRACT_MIN(start, start + numOfRows, *v, p);
218
0
    } else {
219
0
      __COMPARE_EXTRACT_MAX(start, start + numOfRows, *v, p);
220
0
    }
221
0
  }
222
223
0
  pBuf->assign = true;
224
0
}
225
226
static void handleFloatCol(SColumnInfoData* pCol, int32_t start, int32_t numOfRows, SMinmaxResInfo* pBuf,
227
0
                           bool isMinFunc) {
228
0
  float* pData = (float*)pCol->pData;
229
0
  float* val = (float*)&pBuf->v;
230
0
  if (!pBuf->assign) {
231
0
    *val = pData[start];
232
0
  }
233
234
0
  if (tsAVX2Supported && tsSIMDEnable && numOfRows * sizeof(float) >= M256_BYTES) {
235
0
    int32_t code = floatVectorCmpAVX2(pData + start, numOfRows, isMinFunc, val);
236
0
    if (code == TSDB_CODE_SUCCESS) {
237
0
      pBuf->assign = true;
238
0
      return;
239
0
    }
240
0
  }
241
242
0
  if (isMinFunc) {  // min
243
0
    __COMPARE_EXTRACT_MIN(start, start + numOfRows, *val, pData);
244
0
  } else {  // max
245
0
    __COMPARE_EXTRACT_MAX(start, start + numOfRows, *val, pData);
246
0
  }
247
248
0
  pBuf->assign = true;
249
0
}
250
251
static void handleDoubleCol(SColumnInfoData* pCol, int32_t start, int32_t numOfRows, SMinmaxResInfo* pBuf,
252
0
                            bool isMinFunc) {
253
0
  double* pData = (double*)pCol->pData;
254
0
  double* val = (double*)&pBuf->v;
255
0
  if (!pBuf->assign) {
256
0
    *val = pData[start];
257
0
  }
258
259
0
  if (tsAVX2Supported && tsSIMDEnable && numOfRows * sizeof(double) >= M256_BYTES) {
260
0
    int32_t code = doubleVectorCmpAVX2(pData + start, numOfRows, isMinFunc, val);
261
0
    if (code == TSDB_CODE_SUCCESS) {
262
0
      pBuf->assign = true;
263
0
      return;
264
0
    }
265
0
  }
266
267
0
  if (isMinFunc) {  // min
268
0
    __COMPARE_EXTRACT_MIN(start, start + numOfRows, *val, pData);
269
0
  } else {  // max
270
0
    __COMPARE_EXTRACT_MAX(start, start + numOfRows, *val, pData);
271
0
  }
272
273
0
  pBuf->assign = true;
274
0
}
275
276
0
static int32_t findRowIndex(int32_t start, int32_t num, SColumnInfoData* pCol, const char* tval) {
277
0
  // the data is loaded, not only the block SMA value
278
0
  for (int32_t i = start; i < num + start; ++i) {
279
0
    char* p = colDataGetData(pCol, i);
280
0
    if (memcmp((void*)tval, p, pCol->info.bytes) == 0) {
281
0
      return i;
282
0
    }
283
0
  }
284
0
285
0
  // if reach here means real data of block SMA is not set in pCtx->input.
286
0
  return -1;
287
0
}
288
289
static int32_t doExtractVal(SColumnInfoData* pCol, int32_t i, int32_t end, SqlFunctionCtx* pCtx, SMinmaxResInfo* pBuf,
290
0
                            bool isMinFunc) {
291
0
  if (isMinFunc) {
292
0
    switch (pCol->info.type) {
293
0
      case TSDB_DATA_TYPE_BOOL:
294
0
      case TSDB_DATA_TYPE_TINYINT: {
295
0
        const int8_t* pData = (const int8_t*)pCol->pData;
296
0
        __COMPARE_ACQUIRED_MIN(i, end, pCol->nullbitmap, pData, pCtx, *(int8_t*)&(pBuf->v), &pBuf->tuplePos)
297
0
        break;
298
0
      }
299
300
0
      case TSDB_DATA_TYPE_SMALLINT: {
301
0
        const int16_t* pData = (const int16_t*)pCol->pData;
302
0
        __COMPARE_ACQUIRED_MIN(i, end, pCol->nullbitmap, pData, pCtx, *(int16_t*)&(pBuf->v), &pBuf->tuplePos)
303
0
        break;
304
0
      }
305
306
0
      case TSDB_DATA_TYPE_INT: {
307
0
        const int32_t* pData = (const int32_t*)pCol->pData;
308
0
        __COMPARE_ACQUIRED_MIN(i, end, pCol->nullbitmap, pData, pCtx, *(int32_t*)&(pBuf->v), &pBuf->tuplePos)
309
0
        break;
310
0
      }
311
312
0
      case TSDB_DATA_TYPE_BIGINT:
313
0
      case TSDB_DATA_TYPE_TIMESTAMP: {
314
0
        const int64_t* pData = (const int64_t*)pCol->pData;
315
0
        __COMPARE_ACQUIRED_MIN(i, end, pCol->nullbitmap, pData, pCtx, (pBuf->v), &pBuf->tuplePos)
316
0
        break;
317
0
      }
318
319
0
      case TSDB_DATA_TYPE_UTINYINT: {
320
0
        const uint8_t* pData = (const uint8_t*)pCol->pData;
321
0
        __COMPARE_ACQUIRED_MIN(i, end, pCol->nullbitmap, pData, pCtx, *(uint8_t*)&(pBuf->v), &pBuf->tuplePos)
322
0
        break;
323
0
      }
324
325
0
      case TSDB_DATA_TYPE_USMALLINT: {
326
0
        const uint16_t* pData = (const uint16_t*)pCol->pData;
327
0
        __COMPARE_ACQUIRED_MIN(i, end, pCol->nullbitmap, pData, pCtx, *(uint16_t*)&(pBuf->v), &pBuf->tuplePos)
328
0
        break;
329
0
      }
330
331
0
      case TSDB_DATA_TYPE_UINT: {
332
0
        const uint32_t* pData = (const uint32_t*)pCol->pData;
333
0
        __COMPARE_ACQUIRED_MIN(i, end, pCol->nullbitmap, pData, pCtx, *(uint32_t*)&(pBuf->v), &pBuf->tuplePos)
334
0
        break;
335
0
      }
336
337
0
      case TSDB_DATA_TYPE_UBIGINT: {
338
0
        const uint64_t* pData = (const uint64_t*)pCol->pData;
339
0
        __COMPARE_ACQUIRED_MIN(i, end, pCol->nullbitmap, pData, pCtx, *(uint64_t*)&(pBuf->v), &pBuf->tuplePos)
340
0
        break;
341
0
      }
342
343
0
      case TSDB_DATA_TYPE_FLOAT: {
344
0
        const float* pData = (const float*)pCol->pData;
345
0
        __COMPARE_ACQUIRED_MIN(i, end, pCol->nullbitmap, pData, pCtx, *(float*)&(pBuf->v), &pBuf->tuplePos)
346
0
        break;
347
0
      }
348
349
0
      case TSDB_DATA_TYPE_DOUBLE: {
350
0
        const double* pData = (const double*)pCol->pData;
351
0
        __COMPARE_ACQUIRED_MIN(i, end, pCol->nullbitmap, pData, pCtx, *(double*)&(pBuf->v), &pBuf->tuplePos)
352
0
        break;
353
0
      }
354
355
0
      case TSDB_DATA_TYPE_VARCHAR:
356
0
      case TSDB_DATA_TYPE_VARBINARY: {
357
0
        int32_t code = TSDB_CODE_SUCCESS;
358
0
        for (; i < (end); ++i) {
359
0
          if (colDataIsNull_var(pCol, i)) {
360
0
            continue;
361
0
          }
362
0
          char* pLeft = (char*)colDataGetData(pCol, i);
363
0
          char* pRight = (char*)pBuf->str;
364
365
0
          int32_t ret = compareLenBinaryVal(pLeft, pRight);
366
0
          if (ret < 0) {
367
0
            memcpy(pBuf->str, pLeft, varDataTLen(pLeft));
368
0
            if (pCtx->subsidiaries.num > 0) {
369
0
              code = updateTupleData(pCtx, i, pCtx->pSrcBlock, &pBuf->tuplePos);
370
0
              if (TSDB_CODE_SUCCESS != code) {
371
0
                return code;
372
0
              }
373
0
            }
374
0
          }
375
0
        }
376
0
        break;
377
0
      }
378
0
      case TSDB_DATA_TYPE_NCHAR: {
379
0
        int32_t code = TSDB_CODE_SUCCESS;
380
0
        for (; i < (end); ++i) {
381
0
          if (colDataIsNull_var(pCol, i)) {
382
0
            continue;
383
0
          }
384
0
          char* pLeft = (char*)colDataGetData(pCol, i);
385
0
          char* pRight = (char*)pBuf->str;
386
387
0
          int32_t ret = compareLenPrefixedWStr(pLeft, pRight);
388
0
          if (ret < 0) {
389
0
            memcpy(pBuf->str, pLeft, varDataTLen(pLeft));
390
0
            if (pCtx->subsidiaries.num > 0) {
391
0
              code = updateTupleData(pCtx, i, pCtx->pSrcBlock, &pBuf->tuplePos);
392
0
              if (TSDB_CODE_SUCCESS != code) {
393
0
                return code;
394
0
              }
395
0
            }
396
0
          }
397
0
        }
398
0
        break;
399
0
      }
400
0
      case TSDB_DATA_TYPE_DECIMAL64: {
401
0
        const Decimal64*   pData = (const Decimal64*)pCol->pData;
402
0
        const SDecimalOps* pOps = getDecimalOps(TSDB_DATA_TYPE_DECIMAL64);
403
0
        int32_t            code = 0;
404
0
        for (; i < end; ++i) {
405
0
          if (colDataIsNull_f(pCol, i)) {
406
0
            continue;
407
0
          }
408
0
          if (pOps->gt(&pBuf->v, &pData[i], DECIMAL_WORD_NUM(Decimal64))) {
409
0
            pBuf->v = DECIMAL64_GET_VALUE(&pData[i]);
410
0
            if (pCtx->subsidiaries.num > 0) {
411
0
              code = updateTupleData(pCtx, i, pCtx->pSrcBlock, &pBuf->tuplePos);
412
0
              if (TSDB_CODE_SUCCESS != code) return code;
413
0
            }
414
0
          }
415
0
        }
416
0
      } break;
417
0
      case TSDB_DATA_TYPE_DECIMAL: {
418
0
        int32_t            code = 0;
419
0
        const SDecimalOps* pOps = getDecimalOps(TSDB_DATA_TYPE_DECIMAL);
420
0
        const Decimal128*  pData = (const Decimal128*)pCol->pData;
421
0
        for (; i < end; ++i) {
422
0
          if (colDataIsNull_f(pCol, i)) {
423
0
            continue;
424
0
          }
425
0
          if (pOps->gt(pBuf->dec, &pData[i], DECIMAL_WORD_NUM(Decimal128))) {
426
0
            memcpy(pBuf->dec, pData + i, pCol->info.bytes);
427
0
            if (pCtx->subsidiaries.num > 0) {
428
0
              code = updateTupleData(pCtx, i, pCtx->pSrcBlock, &pBuf->tuplePos);
429
0
              if (TSDB_CODE_SUCCESS != code) return code;
430
0
            }
431
0
          }
432
0
        }
433
0
      } break;
434
0
    }
435
0
  } else {
436
0
    switch (pCol->info.type) {
437
0
      case TSDB_DATA_TYPE_BOOL:
438
0
      case TSDB_DATA_TYPE_TINYINT: {
439
0
        const int8_t* pData = (const int8_t*)pCol->pData;
440
0
        __COMPARE_ACQUIRED_MAX(i, end, pCol->nullbitmap, pData, pCtx, *(int8_t*)&(pBuf->v), &pBuf->tuplePos)
441
0
        break;
442
0
      }
443
444
0
      case TSDB_DATA_TYPE_SMALLINT: {
445
0
        const int16_t* pData = (const int16_t*)pCol->pData;
446
0
        __COMPARE_ACQUIRED_MAX(i, end, pCol->nullbitmap, pData, pCtx, *(int16_t*)&(pBuf->v), &pBuf->tuplePos)
447
0
        break;
448
0
      }
449
450
0
      case TSDB_DATA_TYPE_INT: {
451
0
        const int32_t* pData = (const int32_t*)pCol->pData;
452
0
        __COMPARE_ACQUIRED_MAX(i, end, pCol->nullbitmap, pData, pCtx, *(int32_t*)&(pBuf->v), &pBuf->tuplePos)
453
0
        break;
454
0
      }
455
456
0
      case TSDB_DATA_TYPE_BIGINT: 
457
0
      case TSDB_DATA_TYPE_TIMESTAMP: {
458
0
        const int64_t* pData = (const int64_t*)pCol->pData;
459
0
        __COMPARE_ACQUIRED_MAX(i, end, pCol->nullbitmap, pData, pCtx, (pBuf->v), &pBuf->tuplePos)
460
0
        break;
461
0
      }
462
463
0
      case TSDB_DATA_TYPE_UTINYINT: {
464
0
        const uint8_t* pData = (const uint8_t*)pCol->pData;
465
0
        __COMPARE_ACQUIRED_MAX(i, end, pCol->nullbitmap, pData, pCtx, *(uint8_t*)&(pBuf->v), &pBuf->tuplePos)
466
0
        break;
467
0
      }
468
469
0
      case TSDB_DATA_TYPE_USMALLINT: {
470
0
        const uint16_t* pData = (const uint16_t*)pCol->pData;
471
0
        __COMPARE_ACQUIRED_MAX(i, end, pCol->nullbitmap, pData, pCtx, *(uint16_t*)&(pBuf->v), &pBuf->tuplePos)
472
0
        break;
473
0
      }
474
475
0
      case TSDB_DATA_TYPE_UINT: {
476
0
        const uint32_t* pData = (const uint32_t*)pCol->pData;
477
0
        __COMPARE_ACQUIRED_MAX(i, end, pCol->nullbitmap, pData, pCtx, *(uint32_t*)&(pBuf->v), &pBuf->tuplePos)
478
0
        break;
479
0
      }
480
481
0
      case TSDB_DATA_TYPE_UBIGINT: {
482
0
        const uint64_t* pData = (const uint64_t*)pCol->pData;
483
0
        __COMPARE_ACQUIRED_MAX(i, end, pCol->nullbitmap, pData, pCtx, *(uint64_t*)&(pBuf->v), &pBuf->tuplePos)
484
0
        break;
485
0
      }
486
487
0
      case TSDB_DATA_TYPE_FLOAT: {
488
0
        const float* pData = (const float*)pCol->pData;
489
0
        __COMPARE_ACQUIRED_MAX(i, end, pCol->nullbitmap, pData, pCtx, *(float*)&(pBuf->v), &pBuf->tuplePos)
490
0
        break;
491
0
      }
492
493
0
      case TSDB_DATA_TYPE_DOUBLE: {
494
0
        const double* pData = (const double*)pCol->pData;
495
0
        __COMPARE_ACQUIRED_MAX(i, end, pCol->nullbitmap, pData, pCtx, *(double*)&(pBuf->v), &pBuf->tuplePos)
496
0
        break;
497
0
      }
498
0
      case TSDB_DATA_TYPE_DECIMAL64: {
499
0
        const Decimal64* pData = (const Decimal64*)pCol->pData;
500
0
        const SDecimalOps* pOps = getDecimalOps(TSDB_DATA_TYPE_DECIMAL64);
501
0
        int32_t code = 0;
502
0
        for (; i < end; ++i) {
503
0
          if (colDataIsNull_f(pCol, i)) {
504
0
            continue;
505
0
          }
506
0
          if (pOps->lt(&pBuf->v, &pData[i], DECIMAL_WORD_NUM(Decimal64))) {
507
0
            pBuf->v = DECIMAL64_GET_VALUE(&pData[i]);
508
0
            if (pCtx->subsidiaries.num > 0) {
509
0
              code = updateTupleData(pCtx, i, pCtx->pSrcBlock, &pBuf->tuplePos);
510
0
              if (TSDB_CODE_SUCCESS != code) return code;
511
0
            }
512
0
          }
513
0
        }
514
0
      } break;
515
0
      case TSDB_DATA_TYPE_DECIMAL: {
516
0
        int32_t            code = 0;
517
0
        const SDecimalOps* pOps = getDecimalOps(TSDB_DATA_TYPE_DECIMAL);
518
0
        const Decimal128*  pData = (const Decimal128*)pCol->pData;
519
0
        for (; i < end; ++i) {
520
0
          if (colDataIsNull_f(pCol, i)) {
521
0
            continue;
522
0
          }
523
0
          if (pOps->lt(pBuf->dec, &pData[i], DECIMAL_WORD_NUM(Decimal128))) {
524
0
            memcpy(pBuf->dec, pData + i, pCol->info.bytes);
525
0
            if (pCtx->subsidiaries.num > 0) {
526
0
              code = updateTupleData(pCtx, i, pCtx->pSrcBlock, &pBuf->tuplePos);
527
0
              if (TSDB_CODE_SUCCESS != code) return code;
528
0
            }
529
0
          }
530
0
        }
531
0
      } break;
532
533
0
      case TSDB_DATA_TYPE_VARCHAR:
534
0
      case TSDB_DATA_TYPE_VARBINARY: {
535
0
        int32_t code = TSDB_CODE_SUCCESS;
536
0
        for (; i < (end); ++i) {
537
0
          if (colDataIsNull_var(pCol, i)) {
538
0
            continue;
539
0
          }
540
0
          char* pLeft = (char*)colDataGetData(pCol, i);
541
0
          char* pRight = (char*)pBuf->str;
542
543
0
          int32_t ret = compareLenBinaryVal(pLeft, pRight);
544
0
          if (ret > 0) {
545
0
            memcpy(pBuf->str, pLeft, varDataTLen(pLeft));
546
0
            if (pCtx->subsidiaries.num > 0) {
547
0
              code = updateTupleData(pCtx, i, pCtx->pSrcBlock, &pBuf->tuplePos);
548
0
              if (TSDB_CODE_SUCCESS != code) {
549
0
                return code;
550
0
              }
551
0
            }
552
0
          }
553
0
        }
554
0
        break;
555
0
      }
556
557
0
      case TSDB_DATA_TYPE_NCHAR: {
558
0
        int32_t code = TSDB_CODE_SUCCESS;
559
0
        for (; i < (end); ++i) {
560
0
          if (colDataIsNull_var(pCol, i)) {
561
0
            continue;
562
0
          }
563
0
          char* pLeft = (char*)colDataGetData(pCol, i);
564
0
          char* pRight = (char*)pBuf->str;
565
566
0
          int32_t ret = compareLenPrefixedWStr(pLeft, pRight);
567
0
          if (ret > 0) {
568
0
            memcpy(pBuf->str, pLeft, varDataTLen(pLeft));
569
0
            if (pCtx->subsidiaries.num > 0) {
570
0
              code = updateTupleData(pCtx, i, pCtx->pSrcBlock, &pBuf->tuplePos);
571
0
              if (TSDB_CODE_SUCCESS != code) {
572
0
                return code;
573
0
              }
574
0
            }
575
0
          }
576
0
        }
577
0
        break;
578
0
      }
579
0
    }
580
0
  }
581
0
  return TSDB_CODE_SUCCESS;
582
0
}
583
584
0
static int32_t saveRelatedTupleTag(SqlFunctionCtx* pCtx, SInputColumnInfoData* pInput, void* tval) {
585
0
  SColumnInfoData* pCol = pInput->pData[0];
586
587
0
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
588
0
  SMinmaxResInfo*      pBuf = GET_ROWCELL_INTERBUF(pResInfo);
589
590
0
  int32_t code = TSDB_CODE_SUCCESS;
591
0
  if (pCtx->subsidiaries.num > 0) {
592
0
    code = saveTupleData(pCtx, 0, pCtx->pSrcBlock, &pBuf->tuplePos);
593
0
  }
594
0
  return code;
595
0
}
596
597
0
int32_t doMinMaxHelper(SqlFunctionCtx* pCtx, int32_t isMinFunc, int32_t* nElems) {
598
0
  int32_t numOfElems = 0;
599
0
  int32_t code = TSDB_CODE_SUCCESS;
600
601
0
  SInputColumnInfoData* pInput = &pCtx->input;
602
0
  SColumnDataAgg*       pAgg = pInput->pColumnDataAgg[0];
603
604
0
  SColumnInfoData* pCol = pInput->pData[0];
605
0
  int32_t          type = pCol->info.type;
606
607
0
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
608
0
  SMinmaxResInfo*      pBuf = GET_ROWCELL_INTERBUF(pResInfo);
609
0
  pBuf->type = type;
610
611
0
  if (IS_NULL_TYPE(type)) {
612
0
    goto _over;
613
0
  }
614
615
  // data in current data block are qualified to the query
616
0
  if (pInput->colDataSMAIsSet && !IS_STR_DATA_TYPE(type)) {
617
0
    numOfElems = pInput->numOfRows - pAgg->numOfNull;
618
0
    if (numOfElems == 0) {
619
0
      goto _over;
620
0
    }
621
622
0
    int16_t index = 0;
623
0
    void*   tval = NULL;
624
0
    if (IS_DECIMAL_TYPE(type)) {
625
0
      tval = isMinFunc ? pInput->pColumnDataAgg[0]->decimal128Min : pInput->pColumnDataAgg[0]->decimal128Max;
626
0
    } else {
627
0
      tval = (isMinFunc) ? &pInput->pColumnDataAgg[0]->min : &pInput->pColumnDataAgg[0]->max;
628
0
    }
629
630
0
    if (!pBuf->assign) {
631
0
      if (type == TSDB_DATA_TYPE_FLOAT) {
632
0
        GET_FLOAT_VAL(&pBuf->v) = GET_DOUBLE_VAL(tval);
633
0
      } else if (type == TSDB_DATA_TYPE_DECIMAL) {
634
0
        memcpy(pBuf->dec, tval, pCol->info.bytes);
635
0
      } else {
636
0
        pBuf->v = GET_INT64_VAL(tval);
637
0
      }
638
639
0
      code = saveRelatedTupleTag(pCtx, pInput, tval);
640
0
    } else {
641
0
      if (IS_SIGNED_NUMERIC_TYPE(type) || TSDB_DATA_TYPE_BOOL == type || TSDB_DATA_TYPE_TIMESTAMP == type) {
642
0
        int64_t prev = 0;
643
0
        GET_TYPED_DATA(prev, int64_t, type, &pBuf->v, 0);
644
645
0
        int64_t val = GET_INT64_VAL(tval);
646
0
        if ((prev < val) ^ isMinFunc) {
647
0
          GET_INT64_VAL(&pBuf->v) = val;
648
0
          code = saveRelatedTupleTag(pCtx, pInput, tval);
649
0
        }
650
0
      } else if (IS_UNSIGNED_NUMERIC_TYPE(type)) {
651
0
        uint64_t prev = 0;
652
0
        GET_TYPED_DATA(prev, uint64_t, type, &pBuf->v, 0);
653
654
0
        uint64_t val = GET_UINT64_VAL(tval);
655
0
        if ((prev < val) ^ isMinFunc) {
656
0
          GET_UINT64_VAL(&pBuf->v) = val;
657
0
          code = saveRelatedTupleTag(pCtx, pInput, tval);
658
0
        }
659
0
      } else if (type == TSDB_DATA_TYPE_DOUBLE) {
660
0
        double prev = 0;
661
0
        GET_TYPED_DATA(prev, double, type, &pBuf->v, 0);
662
663
0
        double val = GET_DOUBLE_VAL(tval);
664
0
        if ((prev < val) ^ isMinFunc) {
665
0
          GET_DOUBLE_VAL(&pBuf->v) = val;
666
0
          code = saveRelatedTupleTag(pCtx, pInput, tval);
667
0
        }
668
0
      } else if (type == TSDB_DATA_TYPE_FLOAT) {
669
0
        float prev = 0;
670
0
        GET_TYPED_DATA(prev, float, type, &pBuf->v, 0);
671
672
0
        float val = GET_DOUBLE_VAL(tval);
673
0
        if ((prev < val) ^ isMinFunc) {
674
0
          GET_FLOAT_VAL(&pBuf->v) = val;
675
0
          code = saveRelatedTupleTag(pCtx, pInput, tval);
676
0
        }
677
0
      } else if (type == TSDB_DATA_TYPE_DECIMAL64) {
678
0
        const SDecimalOps* pOps = getDecimalOps(type);
679
0
        if (pOps->lt(&pBuf->v, tval, DECIMAL_WORD_NUM(Decimal64)) ^ isMinFunc) {
680
0
          DECIMAL64_SET_VALUE((Decimal64*)&pBuf->v, *(int64_t*)tval);
681
0
          code =saveRelatedTupleTag(pCtx, pInput, tval);
682
0
        }
683
0
      } else if (type == TSDB_DATA_TYPE_DECIMAL) {
684
0
        const SDecimalOps* pOps = getDecimalOps(type);
685
0
        if (pOps->lt(pBuf->dec, tval, DECIMAL_WORD_NUM(Decimal128)) ^ isMinFunc) {
686
0
          DECIMAL128_CLONE((Decimal128*)pBuf->dec, (Decimal128*)tval);
687
0
          code =saveRelatedTupleTag(pCtx, pInput, tval);
688
0
        }
689
0
      }
690
0
    }
691
692
0
    numOfElems = 1;
693
0
    pBuf->assign = true;
694
0
    goto _over;
695
0
  }
696
697
0
  int32_t start = pInput->startRowIndex;
698
0
  int32_t numOfRows = pInput->numOfRows;
699
0
  int32_t end = start + numOfRows;
700
701
  // clang-format off
702
0
  int32_t threshold[] = {
703
      //NULL,    BOOL,      TINYINT, SMALLINT, INT, BIGINT, FLOAT, DOUBLE, VARCHAR,   TIMESTAMP, NCHAR,
704
0
      INT32_MAX, 32,        32,      16,       8,   4,      8,     4,      INT32_MAX, 4,         INT32_MAX,
705
      // UTINYINT,USMALLINT, UINT, UBIGINT,   JSON,      VARBINARY, DECIMAL,   BLOB,      MEDIUMBLOB, BINARY,   Decimal64
706
0
      32,         16,        8,    4,         INT32_MAX, INT32_MAX, INT32_MAX, INT32_MAX, INT32_MAX,  INT32_MAX, INT32_MAX,
707
0
  };
708
  // clang-format on
709
710
0
  if (pCol->hasNull || numOfRows < threshold[pCol->info.type] || pCtx->subsidiaries.num > 0) {
711
0
    int32_t i = findFirstValPosition(pCol, start, numOfRows, IS_STR_DATA_TYPE(type));
712
713
0
    if ((i < end) && (!pBuf->assign)) {
714
0
      char* p = pCol->pData + pCol->info.bytes * i;
715
716
0
      switch (type) {
717
0
        case TSDB_DATA_TYPE_DOUBLE:
718
0
        case TSDB_DATA_TYPE_UBIGINT:
719
0
        case TSDB_DATA_TYPE_BIGINT:
720
0
        case TSDB_DATA_TYPE_TIMESTAMP:
721
0
          pBuf->v = *(int64_t*)p;
722
0
          break;
723
0
        case TSDB_DATA_TYPE_UINT:
724
0
        case TSDB_DATA_TYPE_INT:
725
0
          pBuf->v = *(int32_t*)p;
726
0
          break;
727
0
        case TSDB_DATA_TYPE_USMALLINT:
728
0
        case TSDB_DATA_TYPE_SMALLINT:
729
0
          pBuf->v = *(int16_t*)p;
730
0
          break;
731
0
        case TSDB_DATA_TYPE_BOOL:
732
0
        case TSDB_DATA_TYPE_UTINYINT:
733
0
        case TSDB_DATA_TYPE_TINYINT:
734
0
          pBuf->v = *(int8_t*)p;
735
0
          break;
736
0
        case TSDB_DATA_TYPE_FLOAT: {
737
0
          *(float*)&pBuf->v = *(float*)p;
738
0
          break;
739
0
        }
740
0
        case TSDB_DATA_TYPE_VARCHAR:
741
0
        case TSDB_DATA_TYPE_VARBINARY:
742
0
        case TSDB_DATA_TYPE_NCHAR: {
743
0
          pBuf->str = taosMemoryMalloc(pCol->info.bytes);
744
0
          if (pBuf->str == NULL) {
745
0
            return terrno;
746
0
          }
747
0
          (void)memcpy(pBuf->str, colDataGetData(pCol, i), varDataTLen(colDataGetData(pCol, i)));
748
0
          break;
749
0
        }
750
0
        case TSDB_DATA_TYPE_DECIMAL64:
751
0
          *(int64_t*)&pBuf->v = *(int64_t*)p;
752
0
          break;
753
0
        case TSDB_DATA_TYPE_DECIMAL:
754
0
          (void)memcpy(pBuf->dec, p, pCol->info.bytes);
755
0
          break;
756
0
        default:
757
0
          (void)memcpy(&pBuf->v, p, pCol->info.bytes);
758
0
          break;
759
0
      }
760
761
0
      if (pCtx->subsidiaries.num > 0) {
762
0
        code = saveTupleData(pCtx, i, pCtx->pSrcBlock, &pBuf->tuplePos);
763
0
        if (code != TSDB_CODE_SUCCESS) {
764
0
          return code;
765
0
        }
766
0
      }
767
0
      pBuf->assign = true;
768
0
      numOfElems = 1;
769
0
    }
770
771
0
    if (i >= end) {
772
0
      goto _over;
773
0
    }
774
775
0
    code = doExtractVal(pCol, i, end, pCtx, pBuf, isMinFunc);
776
0
  } else {
777
0
    numOfElems = numOfRows;
778
779
0
    switch (type) {
780
0
      case TSDB_DATA_TYPE_BOOL:
781
0
      case TSDB_DATA_TYPE_TINYINT: {
782
0
        handleInt8Col(pCol->pData, start, numOfRows, pBuf, isMinFunc, true);
783
0
        break;
784
0
      }
785
0
      case TSDB_DATA_TYPE_SMALLINT: {
786
0
        handleInt16Col(pCol->pData, start, numOfRows, pBuf, isMinFunc, true);
787
0
        break;
788
0
      }
789
0
      case TSDB_DATA_TYPE_INT: {
790
0
        handleInt32Col(pCol->pData, start, numOfRows, pBuf, isMinFunc, true);
791
0
        break;
792
0
      }
793
0
      case TSDB_DATA_TYPE_BIGINT:
794
0
      case TSDB_DATA_TYPE_TIMESTAMP: {
795
0
        handleInt64Col(pCol->pData, start, numOfRows, pBuf, isMinFunc, true);
796
0
        break;
797
0
      }
798
0
      case TSDB_DATA_TYPE_UTINYINT: {
799
0
        handleInt8Col(pCol->pData, start, numOfRows, pBuf, isMinFunc, false);
800
0
        break;
801
0
      }
802
0
      case TSDB_DATA_TYPE_USMALLINT: {
803
0
        handleInt16Col(pCol->pData, start, numOfRows, pBuf, isMinFunc, false);
804
0
        break;
805
0
      }
806
0
      case TSDB_DATA_TYPE_UINT: {
807
0
        handleInt32Col(pCol->pData, start, numOfRows, pBuf, isMinFunc, false);
808
0
        break;
809
0
      }
810
0
      case TSDB_DATA_TYPE_UBIGINT: {
811
0
        handleInt64Col(pCol->pData, start, numOfRows, pBuf, isMinFunc, false);
812
0
        break;
813
0
      }
814
0
      case TSDB_DATA_TYPE_FLOAT: {
815
0
        handleFloatCol(pCol, start, numOfRows, pBuf, isMinFunc);
816
0
        break;
817
0
      }
818
0
      case TSDB_DATA_TYPE_DOUBLE: {
819
0
        handleDoubleCol(pCol, start, numOfRows, pBuf, isMinFunc);
820
0
        break;
821
0
      }
822
0
    }
823
824
0
    pBuf->assign = true;
825
0
  }
826
827
0
_over:
828
0
  if (numOfElems == 0 && pCtx->subsidiaries.num > 0 && !pBuf->nullTupleSaved) {
829
0
    code = saveTupleData(pCtx, pInput->startRowIndex, pCtx->pSrcBlock, &pBuf->nullTuplePos);
830
0
    if (code != TSDB_CODE_SUCCESS) {
831
0
      return code;
832
0
    }
833
834
0
    pBuf->nullTupleSaved = true;
835
0
  }
836
837
0
  *nElems = numOfElems;
838
0
  return code;
839
0
}