/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 | } |