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

#include "builtinsimpl.h"
17
#include "function.h"
18
#include "querynodes.h"
H
Haojun Liao 已提交
19 20
#include "taggfunction.h"
#include "tdatablock.h"
21
#include "tpercentile.h"
H
Haojun Liao 已提交
22

G
Ganlin Zhao 已提交
23 24 25 26 27 28 29 30 31 32 33 34 35 36
typedef struct SSumRes {
  union {
    int64_t  isum;
    uint64_t usum;
    double   dsum;
  };
} SSumRes;

typedef struct SAvgRes {
  double  result;
  SSumRes sum;
  int64_t count;
} SAvgRes;

37 38
typedef struct STopBotResItem {
  SVariant v;
39
  uint64_t uid;  // it is a table uid, used to extract tag data during building of the final result for the tag data
40
  struct {
41 42 43
    int32_t pageId;
    int32_t offset;
  } tuplePos;  // tuple data of this chosen row
44 45
} STopBotResItem;

G
Ganlin Zhao 已提交
46
typedef struct STopBotRes {
47
  STopBotResItem* pItems;
G
Ganlin Zhao 已提交
48 49 50 51 52
} STopBotRes;

typedef struct SStddevRes {
  double  result;
  int64_t count;
53 54 55 56 57 58 59 60
  union {
    double  quadraticDSum;
    int64_t quadraticISum;
  };
  union {
    double  dsum;
    int64_t isum;
  };
G
Ganlin Zhao 已提交
61 62 63 64
} SStddevRes;

typedef struct SPercentileInfo {
  double      result;
65
  tMemBucket* pMemBucket;
G
Ganlin Zhao 已提交
66 67 68 69 70 71 72
  int32_t     stage;
  double      minval;
  double      maxval;
  int64_t     numOfElems;
} SPercentileInfo;

typedef struct SDiffInfo {
73 74 75 76 77 78 79 80
  bool hasPrev;
  bool includeNull;
  bool ignoreNegative;
  bool firstOutput;
  union {
    int64_t i64;
    double  d64;
  } prev;
G
Ganlin Zhao 已提交
81 82
} SDiffInfo;

83 84 85 86 87 88
#define SET_VAL(_info, numOfElem, res) \
  do {                                 \
    if ((numOfElem) <= 0) {            \
      break;                           \
    }                                  \
    (_info)->numOfRes = (res);         \
H
Haojun Liao 已提交
89 90
  } while (0)

G
Ganlin Zhao 已提交
91 92 93 94 95 96
#define GET_TS_LIST(x)    ((TSKEY*)((x)->ptsList))
#define GET_TS_DATA(x, y) (GET_TS_LIST(x)[(y)])

#define DO_UPDATE_TAG_COLUMNS_WITHOUT_TS(ctx)                      \
  do {                                                             \
    for (int32_t _i = 0; _i < (ctx)->tagInfo.numOfTagCols; ++_i) { \
97
      SqlFunctionCtx* __ctx = (ctx)->tagInfo.pTagCtxList[_i];      \
G
Ganlin Zhao 已提交
98 99 100 101 102 103 104 105 106 107 108 109 110 111 112
      __ctx->fpSet.process(__ctx);                                 \
    }                                                              \
  } while (0);

#define UPDATE_DATA(ctx, left, right, num, sign, _ts) \
  do {                                                \
    if (((left) < (right)) ^ (sign)) {                \
      (left) = (right);                               \
      DO_UPDATE_SUBSID_RES(ctx, _ts);                 \
      (num) += 1;                                     \
    }                                                 \
  } while (0)

#define LOOPCHECK_N(val, _col, ctx, _t, _nrow, _start, sign, num)        \
  do {                                                                   \
113
    _t* d = (_t*)((_col)->pData);                                        \
G
Ganlin Zhao 已提交
114 115 116 117 118 119 120 121 122
    for (int32_t i = (_start); i < (_nrow) + (_start); ++i) {            \
      if (((_col)->hasNull) && colDataIsNull_f((_col)->nullbitmap, i)) { \
        continue;                                                        \
      }                                                                  \
      TSKEY ts = (ctx)->ptsList != NULL ? GET_TS_DATA(ctx, i) : 0;       \
      UPDATE_DATA(ctx, val, d[i], num, sign, ts);                        \
    }                                                                    \
  } while (0)

123
bool functionSetup(SqlFunctionCtx* pCtx, SResultRowEntryInfo* pResultInfo) {
H
Haojun Liao 已提交
124 125 126 127 128 129 130 131 132 133 134 135
  if (pResultInfo->initialized) {
    return false;
  }

  if (pCtx->pOutput != NULL) {
    memset(pCtx->pOutput, 0, (size_t)pCtx->resDataInfo.bytes);
  }

  initResultRowEntry(pResultInfo, pCtx->resDataInfo.interBufSize);
  return true;
}

136
int32_t functionFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
137
  int32_t          slotId = pCtx->pExpr->base.resSchema.slotId;
138
  SColumnInfoData* pCol = taosArrayGet(pBlock->pDataBlock, slotId);
139

140
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
141 142
  pResInfo->isNullRes = (pResInfo->numOfRes == 0) ? 1 : 0;
  /*cleanupResultRowEntry(pResInfo);*/
143 144 145 146 147

  char* in = GET_ROWCELL_INTERBUF(pResInfo);
  colDataAppend(pCol, pBlock->info.rows, in, pResInfo->isNullRes);

  return pResInfo->numOfRes;
H
Haojun Liao 已提交
148 149
}

150
int32_t functionFinalizeWithResultBuf(SqlFunctionCtx* pCtx, SSDataBlock* pBlock, char* finalResult) {
151
  int32_t          slotId = pCtx->pExpr->base.resSchema.slotId;
152 153 154
  SColumnInfoData* pCol = taosArrayGet(pBlock->pDataBlock, slotId);

  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
155
  pResInfo->isNullRes = (pResInfo->numOfRes == 0) ? 1 : 0;
156 157 158 159 160 161 162 163
  cleanupResultRowEntry(pResInfo);

  char* in = finalResult;
  colDataAppend(pCol, pBlock->info.rows, in, pResInfo->isNullRes);

  return pResInfo->numOfRes;
}

164 165 166
EFuncDataRequired countDataRequired(SFunctionNode* pFunc, STimeWindow* pTimeWindow) {
  SNode* pParam = nodesListGetNode(pFunc->pParameterList, 0);
  if (QUERY_NODE_COLUMN == nodeType(pParam) && PRIMARYKEY_TIMESTAMP_COL_ID == ((SColumnNode*)pParam)->colId) {
167
    return FUNC_DATA_REQUIRED_NOT_LOAD;
168
  }
169
  return FUNC_DATA_REQUIRED_STATIS_LOAD;
170
}
H
Haojun Liao 已提交
171 172 173 174 175 176 177 178 179 180

bool getCountFuncEnv(SFunctionNode* UNUSED_PARAM(pFunc), SFuncExecEnv* pEnv) {
  pEnv->calcMemSize = sizeof(int64_t);
  return true;
}

/*
 * count function does need the finalize, if data is missing, the default value, which is 0, is used
 * count function does not use the pCtx->interResBuf to keep the intermediate buffer
 */
181
int32_t countFunction(SqlFunctionCtx* pCtx) {
H
Haojun Liao 已提交
182 183 184
  int32_t numOfElem = 0;

  /*
H
Haojun Liao 已提交
185 186 187
   * 1. column data missing (schema modified) causes pInputCol->hasNull == true. pInput->colDataAggIsSet == true;
   * 2. for general non-primary key columns, pInputCol->hasNull may be true or false, pInput->colDataAggIsSet == true;
   * 3. for primary key column, pInputCol->hasNull always be false, pInput->colDataAggIsSet == false;
H
Haojun Liao 已提交
188 189
   */
  SInputColumnInfoData* pInput = &pCtx->input;
190
  SColumnInfoData*      pInputCol = pInput->pData[0];
H
Haojun Liao 已提交
191 192 193 194 195 196 197 198 199 200 201 202
  if (pInput->colDataAggIsSet && pInput->totalRows == pInput->numOfRows) {
    numOfElem = pInput->numOfRows - pInput->pColumnDataAgg[0]->numOfNull;
    ASSERT(numOfElem >= 0);
  } else {
    if (pInputCol->hasNull) {
      for (int32_t i = pInput->startRowIndex; i < pInput->startRowIndex + pInput->numOfRows; ++i) {
        if (colDataIsNull(pInputCol, pInput->totalRows, i, NULL)) {
          continue;
        }
        numOfElem += 1;
      }
    } else {
203 204
      // when counting on the primary time stamp column and no statistics data is presented, use the size value
      // directly.
H
Haojun Liao 已提交
205 206 207 208 209
      numOfElem = pInput->numOfRows;
    }
  }

  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
210 211
  char*                buf = GET_ROWCELL_INTERBUF(pResInfo);
  *((int64_t*)buf) += numOfElem;
H
Haojun Liao 已提交
212 213

  SET_VAL(pResInfo, numOfElem, 1);
wmmhello's avatar
wmmhello 已提交
214
  return TSDB_CODE_SUCCESS;
H
Haojun Liao 已提交
215 216 217 218
}

#define LIST_ADD_N(_res, _col, _start, _rows, _t, numOfElem)             \
  do {                                                                   \
219
    _t* d = (_t*)(_col->pData);                                          \
H
Haojun Liao 已提交
220 221 222 223 224 225 226 227 228
    for (int32_t i = (_start); i < (_rows) + (_start); ++i) {            \
      if (((_col)->hasNull) && colDataIsNull_f((_col)->nullbitmap, i)) { \
        continue;                                                        \
      };                                                                 \
      (_res) += (d)[i];                                                  \
      (numOfElem)++;                                                     \
    }                                                                    \
  } while (0)

229
int32_t sumFunction(SqlFunctionCtx* pCtx) {
H
Haojun Liao 已提交
230 231 232 233
  int32_t numOfElem = 0;

  // Only the pre-computing information loaded and actual data does not loaded
  SInputColumnInfoData* pInput = &pCtx->input;
234 235
  SColumnDataAgg*       pAgg = pInput->pColumnDataAgg[0];
  int32_t               type = pInput->pData[0]->info.type;
H
Haojun Liao 已提交
236

237
  SSumRes* pSumRes = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
G
Ganlin Zhao 已提交
238

H
Haojun Liao 已提交
239 240 241 242 243
  if (pInput->colDataAggIsSet) {
    numOfElem = pInput->numOfRows - pAgg->numOfNull;
    ASSERT(numOfElem >= 0);

    if (IS_SIGNED_NUMERIC_TYPE(type)) {
244
      pSumRes->isum += pAgg->sum;
H
Haojun Liao 已提交
245
    } else if (IS_UNSIGNED_NUMERIC_TYPE(type)) {
246
      pSumRes->usum += pAgg->sum;
H
Haojun Liao 已提交
247
    } else if (IS_FLOAT_TYPE(type)) {
248
      pSumRes->dsum += GET_DOUBLE_VAL((const char*)&(pAgg->sum));
H
Haojun Liao 已提交
249 250 251 252
    }
  } else {  // computing based on the true data block
    SColumnInfoData* pCol = pInput->pData[0];

253
    int32_t start = pInput->startRowIndex;
H
Haojun Liao 已提交
254 255
    int32_t numOfRows = pInput->numOfRows;

256 257
    if (IS_SIGNED_NUMERIC_TYPE(type) || type == TSDB_DATA_TYPE_BOOL) {
      if (type == TSDB_DATA_TYPE_TINYINT || type == TSDB_DATA_TYPE_BOOL) {
258 259 260 261 262 263 264
        LIST_ADD_N(pSumRes->isum, pCol, start, numOfRows, int8_t, numOfElem);
      } else if (type == TSDB_DATA_TYPE_SMALLINT) {
        LIST_ADD_N(pSumRes->isum, pCol, start, numOfRows, int16_t, numOfElem);
      } else if (type == TSDB_DATA_TYPE_INT) {
        LIST_ADD_N(pSumRes->isum, pCol, start, numOfRows, int32_t, numOfElem);
      } else if (type == TSDB_DATA_TYPE_BIGINT) {
        LIST_ADD_N(pSumRes->isum, pCol, start, numOfRows, int64_t, numOfElem);
H
Haojun Liao 已提交
265
      }
266 267 268 269 270 271 272 273 274
    } else if (IS_UNSIGNED_NUMERIC_TYPE(type)) {
      if (type == TSDB_DATA_TYPE_UTINYINT) {
        LIST_ADD_N(pSumRes->usum, pCol, start, numOfRows, uint8_t, numOfElem);
      } else if (type == TSDB_DATA_TYPE_USMALLINT) {
        LIST_ADD_N(pSumRes->usum, pCol, start, numOfRows, uint16_t, numOfElem);
      } else if (type == TSDB_DATA_TYPE_UINT) {
        LIST_ADD_N(pSumRes->usum, pCol, start, numOfRows, uint32_t, numOfElem);
      } else if (type == TSDB_DATA_TYPE_UBIGINT) {
        LIST_ADD_N(pSumRes->usum, pCol, start, numOfRows, uint64_t, numOfElem);
H
Haojun Liao 已提交
275
      }
276 277 278 279
    } else if (type == TSDB_DATA_TYPE_DOUBLE) {
      LIST_ADD_N(pSumRes->dsum, pCol, start, numOfRows, double, numOfElem);
    } else if (type == TSDB_DATA_TYPE_FLOAT) {
      LIST_ADD_N(pSumRes->dsum, pCol, start, numOfRows, float, numOfElem);
H
Haojun Liao 已提交
280 281 282 283 284
    }
  }

  // data in the check operation are all null, not output
  SET_VAL(GET_RES_INFO(pCtx), numOfElem, 1);
wmmhello's avatar
wmmhello 已提交
285
  return TSDB_CODE_SUCCESS;
H
Haojun Liao 已提交
286 287
}

H
Haojun Liao 已提交
288
bool getSumFuncEnv(SFunctionNode* UNUSED_PARAM(pFunc), SFuncExecEnv* pEnv) {
H
Haojun Liao 已提交
289 290 291 292
  pEnv->calcMemSize = sizeof(SSumRes);
  return true;
}

G
Ganlin Zhao 已提交
293 294 295 296 297
bool getAvgFuncEnv(SFunctionNode* UNUSED_PARAM(pFunc), SFuncExecEnv* pEnv) {
  pEnv->calcMemSize = sizeof(double);
  return true;
}

298
bool avgFunctionSetup(SqlFunctionCtx* pCtx, SResultRowEntryInfo* pResultInfo) {
G
Ganlin Zhao 已提交
299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324
  if (!functionSetup(pCtx, pResultInfo)) {
    return false;
  }

  SAvgRes* pRes = GET_ROWCELL_INTERBUF(pResultInfo);
  memset(pRes, 0, sizeof(SAvgRes));
  return true;
}

int32_t avgFunction(SqlFunctionCtx* pCtx) {
  int32_t numOfElem = 0;

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

  SAvgRes* pAvgRes = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));

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

  int32_t start = pInput->startRowIndex;
  int32_t numOfRows = pInput->numOfRows;

  switch (type) {
    case TSDB_DATA_TYPE_TINYINT: {
325 326 327 328
      int8_t* plist = (int8_t*)pCol->pData;
      for (int32_t i = start; i < numOfRows + pInput->startRowIndex; ++i) {
        if (pCol->hasNull && colDataIsNull_f(pCol->nullbitmap, i)) {
          continue;
G
Ganlin Zhao 已提交
329 330
        }

331 332 333
        numOfElem += 1;
        pAvgRes->count += 1;
        pAvgRes->sum.isum += plist[i];
G
Ganlin Zhao 已提交
334 335
      }

336 337 338 339
      break;
    }

    case TSDB_DATA_TYPE_SMALLINT: {
G
Ganlin Zhao 已提交
340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418
      int16_t* plist = (int16_t*)pCol->pData;
      for (int32_t i = start; i < numOfRows + pInput->startRowIndex; ++i) {
        if (pCol->hasNull && colDataIsNull_f(pCol->nullbitmap, i)) {
          continue;
        }

        numOfElem += 1;
        pAvgRes->count += 1;
        pAvgRes->sum.isum += plist[i];
      }
      break;
    }

    case TSDB_DATA_TYPE_INT: {
      int32_t* plist = (int32_t*)pCol->pData;
      for (int32_t i = start; i < numOfRows + pInput->startRowIndex; ++i) {
        if (pCol->hasNull && colDataIsNull_f(pCol->nullbitmap, i)) {
          continue;
        }

        numOfElem += 1;
        pAvgRes->count += 1;
        pAvgRes->sum.isum += plist[i];
      }

      break;
    }

    case TSDB_DATA_TYPE_BIGINT: {
      int64_t* plist = (int64_t*)pCol->pData;
      for (int32_t i = start; i < numOfRows + pInput->startRowIndex; ++i) {
        if (pCol->hasNull && colDataIsNull_f(pCol->nullbitmap, i)) {
          continue;
        }

        numOfElem += 1;
        pAvgRes->count += 1;
        pAvgRes->sum.isum += plist[i];
      }
      break;
    }

    case TSDB_DATA_TYPE_FLOAT: {
      float* plist = (float*)pCol->pData;
      for (int32_t i = start; i < numOfRows + pInput->startRowIndex; ++i) {
        if (pCol->hasNull && colDataIsNull_f(pCol->nullbitmap, i)) {
          continue;
        }

        numOfElem += 1;
        pAvgRes->count += 1;
        pAvgRes->sum.dsum += plist[i];
      }
      break;
    }

    case TSDB_DATA_TYPE_DOUBLE: {
      double* plist = (double*)pCol->pData;
      for (int32_t i = start; i < numOfRows + pInput->startRowIndex; ++i) {
        if (pCol->hasNull && colDataIsNull_f(pCol->nullbitmap, i)) {
          continue;
        }

        numOfElem += 1;
        pAvgRes->count += 1;
        pAvgRes->sum.dsum += plist[i];
      }
      break;
    }

    default:
      break;
  }

  // data in the check operation are all null, not output
  SET_VAL(GET_RES_INFO(pCtx), numOfElem, 1);
  return TSDB_CODE_SUCCESS;
}

H
Haojun Liao 已提交
419
int32_t avgFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
G
Ganlin Zhao 已提交
420
  SInputColumnInfoData* pInput = &pCtx->input;
421 422
  int32_t               type = pInput->pData[0]->info.type;
  SAvgRes*              pAvgRes = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
G
Ganlin Zhao 已提交
423
  if (IS_INTEGER_TYPE(type)) {
424
    pAvgRes->result = pAvgRes->sum.isum / ((double)pAvgRes->count);
G
Ganlin Zhao 已提交
425
  } else {
426
    pAvgRes->result = pAvgRes->sum.dsum / ((double)pAvgRes->count);
G
Ganlin Zhao 已提交
427
  }
428

H
Haojun Liao 已提交
429
  return functionFinalize(pCtx, pBlock);
G
Ganlin Zhao 已提交
430 431
}

432
EFuncDataRequired statisDataRequired(SFunctionNode* pFunc, STimeWindow* pTimeWindow) {
433 434 435
  return FUNC_DATA_REQUIRED_STATIS_LOAD;
}

436
bool maxFunctionSetup(SqlFunctionCtx* pCtx, SResultRowEntryInfo* pResultInfo) {
437 438 439 440 441
  if (!functionSetup(pCtx, pResultInfo)) {
    return false;
  }

  char* buf = GET_ROWCELL_INTERBUF(pResultInfo);
442
  switch (pCtx->resDataInfo.type) {
443
    case TSDB_DATA_TYPE_INT:
444
      *((int32_t*)buf) = INT32_MIN;
445 446
      break;
    case TSDB_DATA_TYPE_UINT:
447
      *((uint32_t*)buf) = 0;
448 449
      break;
    case TSDB_DATA_TYPE_FLOAT:
450
      *((float*)buf) = -FLT_MAX;
451 452
      break;
    case TSDB_DATA_TYPE_DOUBLE:
453
      SET_DOUBLE_VAL(((double*)buf), -DBL_MAX);
454 455
      break;
    case TSDB_DATA_TYPE_BIGINT:
456
      *((int64_t*)buf) = INT64_MIN;
457 458
      break;
    case TSDB_DATA_TYPE_UBIGINT:
459
      *((uint64_t*)buf) = 0;
460 461
      break;
    case TSDB_DATA_TYPE_SMALLINT:
462
      *((int16_t*)buf) = INT16_MIN;
463 464
      break;
    case TSDB_DATA_TYPE_USMALLINT:
465
      *((uint16_t*)buf) = 0;
466 467
      break;
    case TSDB_DATA_TYPE_TINYINT:
468
      *((int8_t*)buf) = INT8_MIN;
469 470
      break;
    case TSDB_DATA_TYPE_UTINYINT:
471
      *((uint8_t*)buf) = 0;
472
      break;
473 474 475
    case TSDB_DATA_TYPE_BOOL:
      *((int8_t*)buf) = 0;
      break;
476 477 478 479 480 481
    default:
      assert(0);
  }
  return true;
}

482
bool minFunctionSetup(SqlFunctionCtx* pCtx, SResultRowEntryInfo* pResultInfo) {
483 484 485 486 487
  if (!functionSetup(pCtx, pResultInfo)) {
    return false;  // not initialized since it has been initialized
  }

  char* buf = GET_ROWCELL_INTERBUF(pResultInfo);
488
  switch (pCtx->resDataInfo.type) {
489
    case TSDB_DATA_TYPE_TINYINT:
490
      *((int8_t*)buf) = INT8_MAX;
491 492
      break;
    case TSDB_DATA_TYPE_UTINYINT:
493
      *(uint8_t*)buf = UINT8_MAX;
494 495
      break;
    case TSDB_DATA_TYPE_SMALLINT:
496
      *((int16_t*)buf) = INT16_MAX;
497 498
      break;
    case TSDB_DATA_TYPE_USMALLINT:
499
      *((uint16_t*)buf) = UINT16_MAX;
500 501
      break;
    case TSDB_DATA_TYPE_INT:
502
      *((int32_t*)buf) = INT32_MAX;
503 504
      break;
    case TSDB_DATA_TYPE_UINT:
505
      *((uint32_t*)buf) = UINT32_MAX;
506 507
      break;
    case TSDB_DATA_TYPE_BIGINT:
508
      *((int64_t*)buf) = INT64_MAX;
509 510
      break;
    case TSDB_DATA_TYPE_UBIGINT:
511
      *((uint64_t*)buf) = UINT64_MAX;
512 513
      break;
    case TSDB_DATA_TYPE_FLOAT:
514
      *((float*)buf) = FLT_MAX;
515 516
      break;
    case TSDB_DATA_TYPE_DOUBLE:
517
      SET_DOUBLE_VAL(((double*)buf), DBL_MAX);
518
      break;
519 520 521
    case TSDB_DATA_TYPE_BOOL:
      *((int8_t*)buf) = 1;
      break;
522 523 524 525 526 527 528
    default:
      assert(0);
  }

  return true;
}

H
Haojun Liao 已提交
529
bool getMinmaxFuncEnv(SFunctionNode* UNUSED_PARAM(pFunc), SFuncExecEnv* pEnv) {
530 531 532 533 534 535 536 537 538 539
  pEnv->calcMemSize = sizeof(int64_t);
  return true;
}

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

#define DO_UPDATE_TAG_COLUMNS_WITHOUT_TS(ctx)                      \
  do {                                                             \
    for (int32_t _i = 0; _i < (ctx)->tagInfo.numOfTagCols; ++_i) { \
540
      SqlFunctionCtx* __ctx = (ctx)->tagInfo.pTagCtxList[_i];      \
H
Haojun Liao 已提交
541
      __ctx->fpSet.process(__ctx);                                 \
542 543 544
    }                                                              \
  } while (0);

545 546
#define DO_UPDATE_SUBSID_RES(ctx, ts)                          \
  do {                                                         \
547
    for (int32_t _i = 0; _i < (ctx)->subsidiaries.num; ++_i) { \
548 549 550 551 552 553 554
      SqlFunctionCtx* __ctx = (ctx)->subsidiaries.pCtx[_i];    \
      if (__ctx->functionId == FUNCTION_TS_DUMMY) {            \
        __ctx->tag.i = (ts);                                   \
        __ctx->tag.nType = TSDB_DATA_TYPE_BIGINT;              \
      }                                                        \
      __ctx->fpSet.process(__ctx);                             \
    }                                                          \
555 556 557
  } while (0)

#define UPDATE_DATA(ctx, left, right, num, sign, _ts) \
H
Haojun Liao 已提交
558 559 560 561 562 563
  do {                                                \
    if (((left) < (right)) ^ (sign)) {                \
      (left) = (right);                               \
      DO_UPDATE_SUBSID_RES(ctx, _ts);                 \
      (num) += 1;                                     \
    }                                                 \
564 565
  } while (0)

H
Haojun Liao 已提交
566
#define LOOPCHECK_N(val, _col, ctx, _t, _nrow, _start, sign, num)        \
567
  do {                                                                   \
568
    _t* d = (_t*)((_col)->pData);                                        \
569 570 571 572 573 574 575 576 577
    for (int32_t i = (_start); i < (_nrow) + (_start); ++i) {            \
      if (((_col)->hasNull) && colDataIsNull_f((_col)->nullbitmap, i)) { \
        continue;                                                        \
      }                                                                  \
      TSKEY ts = (ctx)->ptsList != NULL ? GET_TS_DATA(ctx, i) : 0;       \
      UPDATE_DATA(ctx, val, d[i], num, sign, ts);                        \
    }                                                                    \
  } while (0)

578
int32_t doMinMaxHelper(SqlFunctionCtx* pCtx, int32_t isMinFunc) {
579 580 581
  int32_t numOfElems = 0;

  SInputColumnInfoData* pInput = &pCtx->input;
582
  SColumnDataAgg*       pAgg = pInput->pColumnDataAgg[0];
583 584

  SColumnInfoData* pCol = pInput->pData[0];
585
  int32_t          type = pCol->info.type;
586 587

  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
588
  char*                buf = GET_ROWCELL_INTERBUF(pResInfo);
589 590 591 592 593 594 595 596 597 598 599 600 601 602

  // data in current data block are qualified to the query
  if (pInput->colDataAggIsSet) {
    numOfElems = pInput->numOfRows - pAgg->numOfNull;
    ASSERT(pInput->numOfRows == pInput->totalRows && numOfElems >= 0);

    if (numOfElems == 0) {
      return numOfElems;
    }

    void*   tval = NULL;
    int16_t index = 0;

    if (isMinFunc) {
603
      tval = &pInput->pColumnDataAgg[0]->min;
604 605
      index = pInput->pColumnDataAgg[0]->minIndex;
    } else {
606
      tval = &pInput->pColumnDataAgg[0]->max;
607 608 609
      index = pInput->pColumnDataAgg[0]->maxIndex;
    }

610
    // the index is the original position, not the relative position
611
    TSKEY key = (pCtx->ptsList != NULL) ? pCtx->ptsList[index] : TSKEY_INITIAL_VAL;
612 613

    if (IS_SIGNED_NUMERIC_TYPE(type)) {
614 615
      int64_t prev = 0;
      GET_TYPED_DATA(prev, int64_t, type, buf);
616

617 618
      int64_t val = GET_INT64_VAL(tval);
      if ((prev < val) ^ isMinFunc) {
619
        *(int64_t*)buf = val;
620 621
        for (int32_t i = 0; i < (pCtx)->subsidiaries.num; ++i) {
          SqlFunctionCtx* __ctx = pCtx->subsidiaries.pCtx[i];
622 623 624 625 626 627 628 629
          if (__ctx->functionId == FUNCTION_TS_DUMMY) {  // TODO refactor
            __ctx->tag.i = key;
            __ctx->tag.nType = TSDB_DATA_TYPE_BIGINT;
          }

          __ctx->fpSet.process(__ctx);
        }
      }
630
    } else if (IS_UNSIGNED_NUMERIC_TYPE(type)) {
631 632 633
      uint64_t prev = 0;
      GET_TYPED_DATA(prev, uint64_t, type, buf);

634
      uint64_t val = GET_UINT64_VAL(tval);
H
Haojun Liao 已提交
635
      if ((prev < val) ^ isMinFunc) {
636
        *(uint64_t*)buf = val;
637 638
        for (int32_t i = 0; i < (pCtx)->subsidiaries.num; ++i) {
          SqlFunctionCtx* __ctx = pCtx->subsidiaries.pCtx[i];
H
Haojun Liao 已提交
639 640 641 642
          if (__ctx->functionId == FUNCTION_TS_DUMMY) {  // TODO refactor
            __ctx->tag.i = key;
            __ctx->tag.nType = TSDB_DATA_TYPE_BIGINT;
          }
643

H
Haojun Liao 已提交
644 645 646 647
          __ctx->fpSet.process(__ctx);
        }
      }
    } else if (type == TSDB_DATA_TYPE_DOUBLE) {
648 649
      double val = GET_DOUBLE_VAL(tval);
      UPDATE_DATA(pCtx, *(double*)buf, val, numOfElems, isMinFunc, key);
650
    } else if (type == TSDB_DATA_TYPE_FLOAT) {
651
      double val = GET_DOUBLE_VAL(tval);
652
      UPDATE_DATA(pCtx, *(float*)buf, val, numOfElems, isMinFunc, key);
653 654 655 656 657 658 659 660
    }

    return numOfElems;
  }

  int32_t start = pInput->startRowIndex;
  int32_t numOfRows = pInput->numOfRows;

661 662
  if (IS_SIGNED_NUMERIC_TYPE(type) || type == TSDB_DATA_TYPE_BOOL) {
    if (type == TSDB_DATA_TYPE_TINYINT || type == TSDB_DATA_TYPE_BOOL) {
663 664
      LOOPCHECK_N(*(int8_t*)buf, pCol, pCtx, int8_t, numOfRows, start, isMinFunc, numOfElems);
    } else if (type == TSDB_DATA_TYPE_SMALLINT) {
665
      LOOPCHECK_N(*(int16_t*)buf, pCol, pCtx, int16_t, numOfRows, start, isMinFunc, numOfElems);
666
    } else if (type == TSDB_DATA_TYPE_INT) {
667 668
      int32_t* pData = (int32_t*)pCol->pData;
      int32_t* val = (int32_t*)buf;
669

H
Haojun Liao 已提交
670
      for (int32_t i = start; i < start + numOfRows; ++i) {
671 672 673 674 675 676
        if ((pCol->hasNull) && colDataIsNull_f(pCol->nullbitmap, i)) {
          continue;
        }

        if ((*val < pData[i]) ^ isMinFunc) {
          *val = pData[i];
677
          TSKEY ts = (pCtx->ptsList != NULL) ? GET_TS_DATA(pCtx, i) : 0;
678 679 680 681 682 683 684 685 686
          DO_UPDATE_SUBSID_RES(pCtx, ts);
        }

        numOfElems += 1;
      }

#if defined(_DEBUG_VIEW)
      qDebug("max value updated:%d", *retVal);
#endif
687
    } else if (type == TSDB_DATA_TYPE_BIGINT) {
688
      LOOPCHECK_N(*(int64_t*)buf, pCol, pCtx, int64_t, numOfRows, start, isMinFunc, numOfElems);
689
    }
690 691
  } else if (IS_UNSIGNED_NUMERIC_TYPE(type)) {
    if (type == TSDB_DATA_TYPE_UTINYINT) {
692
      LOOPCHECK_N(*(uint8_t*)buf, pCol, pCtx, uint8_t, numOfRows, start, isMinFunc, numOfElems);
693
    } else if (type == TSDB_DATA_TYPE_USMALLINT) {
694
      LOOPCHECK_N(*(uint16_t*)buf, pCol, pCtx, uint16_t, numOfRows, start, isMinFunc, numOfElems);
695
    } else if (type == TSDB_DATA_TYPE_UINT) {
696
      LOOPCHECK_N(*(uint32_t*)buf, pCol, pCtx, uint32_t, numOfRows, start, isMinFunc, numOfElems);
697
    } else if (type == TSDB_DATA_TYPE_UBIGINT) {
698
      LOOPCHECK_N(*(uint64_t*)buf, pCol, pCtx, uint64_t, numOfRows, start, isMinFunc, numOfElems);
699
    }
700
  } else if (type == TSDB_DATA_TYPE_DOUBLE) {
701
    LOOPCHECK_N(*(double*)buf, pCol, pCtx, double, numOfRows, start, isMinFunc, numOfElems);
702
  } else if (type == TSDB_DATA_TYPE_FLOAT) {
703
    LOOPCHECK_N(*(float*)buf, pCol, pCtx, float, numOfRows, start, isMinFunc, numOfElems);
704 705 706
  }

  return numOfElems;
H
Haojun Liao 已提交
707
}
708

709
int32_t minFunction(SqlFunctionCtx* pCtx) {
710 711
  int32_t numOfElems = doMinMaxHelper(pCtx, 1);
  SET_VAL(GET_RES_INFO(pCtx), numOfElems, 1);
wmmhello's avatar
wmmhello 已提交
712
  return TSDB_CODE_SUCCESS;
713 714
}

715
int32_t maxFunction(SqlFunctionCtx* pCtx) {
716 717
  int32_t numOfElems = doMinMaxHelper(pCtx, 0);
  SET_VAL(GET_RES_INFO(pCtx), numOfElems, 1);
wmmhello's avatar
wmmhello 已提交
718
  return TSDB_CODE_SUCCESS;
H
Haojun Liao 已提交
719 720 721 722 723 724 725
}

bool getStddevFuncEnv(SFunctionNode* pFunc, SFuncExecEnv* pEnv) {
  pEnv->calcMemSize = sizeof(SStddevRes);
  return true;
}

726
bool stddevFunctionSetup(SqlFunctionCtx* pCtx, SResultRowEntryInfo* pResultInfo) {
H
Haojun Liao 已提交
727 728 729 730 731 732 733 734 735
  if (!functionSetup(pCtx, pResultInfo)) {
    return false;
  }

  SStddevRes* pRes = GET_ROWCELL_INTERBUF(pResultInfo);
  memset(pRes, 0, sizeof(SStddevRes));
  return true;
}

H
Haojun Liao 已提交
736
int32_t stddevFunction(SqlFunctionCtx* pCtx) {
H
Haojun Liao 已提交
737 738 739 740
  int32_t numOfElem = 0;

  // Only the pre-computing information loaded and actual data does not loaded
  SInputColumnInfoData* pInput = &pCtx->input;
H
Haojun Liao 已提交
741
  int32_t               type = pInput->pData[0]->info.type;
H
Haojun Liao 已提交
742 743 744

  SStddevRes* pStddevRes = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));

H
Haojun Liao 已提交
745 746
  // computing based on the true data block
  SColumnInfoData* pCol = pInput->pData[0];
H
Haojun Liao 已提交
747

H
Haojun Liao 已提交
748 749
  int32_t start = pInput->startRowIndex;
  int32_t numOfRows = pInput->numOfRows;
H
Haojun Liao 已提交
750

H
Haojun Liao 已提交
751 752
  switch (type) {
    case TSDB_DATA_TYPE_TINYINT: {
753 754 755 756
      int8_t* plist = (int8_t*)pCol->pData;
      for (int32_t i = start; i < numOfRows + start; ++i) {
        if (pCol->hasNull && colDataIsNull_f(pCol->nullbitmap, i)) {
          continue;
H
Haojun Liao 已提交
757
        }
H
Haojun Liao 已提交
758

759 760 761 762
        numOfElem += 1;
        pStddevRes->count += 1;
        pStddevRes->isum += plist[i];
        pStddevRes->quadraticISum += plist[i] * plist[i];
H
Haojun Liao 已提交
763 764
      }

765 766 767 768
      break;
    }

    case TSDB_DATA_TYPE_SMALLINT: {
H
Haojun Liao 已提交
769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822
      int16_t* plist = (int16_t*)pCol->pData;
      for (int32_t i = start; i < numOfRows + pInput->startRowIndex; ++i) {
        if (pCol->hasNull && colDataIsNull_f(pCol->nullbitmap, i)) {
          continue;
        }

        numOfElem += 1;
        pStddevRes->count += 1;
        pStddevRes->isum += plist[i];
        pStddevRes->quadraticISum += plist[i] * plist[i];
      }
      break;
    }

    case TSDB_DATA_TYPE_INT: {
      int32_t* plist = (int32_t*)pCol->pData;
      for (int32_t i = start; i < numOfRows + pInput->startRowIndex; ++i) {
        if (pCol->hasNull && colDataIsNull_f(pCol->nullbitmap, i)) {
          continue;
        }

        numOfElem += 1;
        pStddevRes->count += 1;
        pStddevRes->isum += plist[i];
        pStddevRes->quadraticISum += plist[i] * plist[i];
      }

      break;
    }

    case TSDB_DATA_TYPE_BIGINT: {
      int64_t* plist = (int64_t*)pCol->pData;
      for (int32_t i = start; i < numOfRows + pInput->startRowIndex; ++i) {
        if (pCol->hasNull && colDataIsNull_f(pCol->nullbitmap, i)) {
          continue;
        }

        numOfElem += 1;
        pStddevRes->count += 1;
        pStddevRes->isum += plist[i];
        pStddevRes->quadraticISum += plist[i] * plist[i];
      }
      break;
    }

    case TSDB_DATA_TYPE_FLOAT: {
      float* plist = (float*)pCol->pData;
      for (int32_t i = start; i < numOfRows + pInput->startRowIndex; ++i) {
        if (pCol->hasNull && colDataIsNull_f(pCol->nullbitmap, i)) {
          continue;
        }

        numOfElem += 1;
        pStddevRes->count += 1;
G
Ganlin Zhao 已提交
823 824
        pStddevRes->dsum += plist[i];
        pStddevRes->quadraticDSum += plist[i] * plist[i];
H
Haojun Liao 已提交
825 826 827 828
      }
      break;
    }

H
Haojun Liao 已提交
829 830 831 832 833 834 835 836 837
    case TSDB_DATA_TYPE_DOUBLE: {
      double* plist = (double*)pCol->pData;
      for (int32_t i = start; i < numOfRows + pInput->startRowIndex; ++i) {
        if (pCol->hasNull && colDataIsNull_f(pCol->nullbitmap, i)) {
          continue;
        }

        numOfElem += 1;
        pStddevRes->count += 1;
G
Ganlin Zhao 已提交
838 839
        pStddevRes->dsum += plist[i];
        pStddevRes->quadraticDSum += plist[i] * plist[i];
H
Haojun Liao 已提交
840 841 842 843 844 845 846 847
      }
      break;
    }

    default:
      break;
  }

H
Haojun Liao 已提交
848 849
  // data in the check operation are all null, not output
  SET_VAL(GET_RES_INFO(pCtx), numOfElem, 1);
wmmhello's avatar
wmmhello 已提交
850
  return TSDB_CODE_SUCCESS;
H
Haojun Liao 已提交
851 852
}

H
Haojun Liao 已提交
853
int32_t stddevFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
G
Ganlin Zhao 已提交
854
  SInputColumnInfoData* pInput = &pCtx->input;
855 856 857
  int32_t               type = pInput->pData[0]->info.type;
  SStddevRes*           pStddevRes = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
  double                avg;
G
Ganlin Zhao 已提交
858
  if (IS_INTEGER_TYPE(type)) {
859 860
    avg = pStddevRes->isum / ((double)pStddevRes->count);
    pStddevRes->result = sqrt(pStddevRes->quadraticISum / ((double)pStddevRes->count) - avg * avg);
G
Ganlin Zhao 已提交
861
  } else {
862 863
    avg = pStddevRes->dsum / ((double)pStddevRes->count);
    pStddevRes->result = sqrt(pStddevRes->quadraticDSum / ((double)pStddevRes->count) - avg * avg);
G
Ganlin Zhao 已提交
864
  }
865

866
  return functionFinalize(pCtx, pBlock);
H
Haojun Liao 已提交
867 868 869 870 871 872 873
}

bool getPercentileFuncEnv(SFunctionNode* pFunc, SFuncExecEnv* pEnv) {
  pEnv->calcMemSize = sizeof(SPercentileInfo);
  return true;
}

874
bool percentileFunctionSetup(SqlFunctionCtx* pCtx, SResultRowEntryInfo* pResultInfo) {
H
Haojun Liao 已提交
875 876 877 878 879
  if (!functionSetup(pCtx, pResultInfo)) {
    return false;
  }

  // in the first round, get the min-max value of all involved data
880
  SPercentileInfo* pInfo = GET_ROWCELL_INTERBUF(pResultInfo);
H
Haojun Liao 已提交
881 882 883 884 885
  SET_DOUBLE_VAL(&pInfo->minval, DBL_MAX);
  SET_DOUBLE_VAL(&pInfo->maxval, -DBL_MAX);
  pInfo->numOfElems = 0;

  return true;
H
Haojun Liao 已提交
886 887
}

888 889 890
int32_t percentileFunction(SqlFunctionCtx* pCtx) {
  int32_t              notNullElems = 0;
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
891 892

  SInputColumnInfoData* pInput = &pCtx->input;
893
  SColumnDataAgg*       pAgg = pInput->pColumnDataAgg[0];
H
Haojun Liao 已提交
894

895 896
  SColumnInfoData* pCol = pInput->pData[0];
  int32_t          type = pCol->info.type;
897

898
  SPercentileInfo* pInfo = GET_ROWCELL_INTERBUF(pResInfo);
H
Haojun Liao 已提交
899 900
  if (pCtx->currentStage == REPEAT_SCAN && pInfo->stage == 0) {
    pInfo->stage += 1;
H
Haojun Liao 已提交
901

H
Haojun Liao 已提交
902 903 904
    // all data are null, set it completed
    if (pInfo->numOfElems == 0) {
      pResInfo->complete = true;
H
Haojun Liao 已提交
905
      return 0;
H
Haojun Liao 已提交
906 907 908 909 910 911 912
    } else {
      pInfo->pMemBucket = tMemBucketCreate(pCtx->inputBytes, pCtx->inputType, pInfo->minval, pInfo->maxval);
    }
  }

  // the first stage, only acquire the min/max value
  if (pInfo->stage == 0) {
913
    if (pCtx->input.colDataAggIsSet) {
H
Haojun Liao 已提交
914
      double tmin = 0.0, tmax = 0.0;
915 916 917 918 919 920 921 922 923
      if (IS_SIGNED_NUMERIC_TYPE(type)) {
        tmin = (double)GET_INT64_VAL(&pAgg->min);
        tmax = (double)GET_INT64_VAL(&pAgg->max);
      } else if (IS_FLOAT_TYPE(type)) {
        tmin = GET_DOUBLE_VAL(&pAgg->min);
        tmax = GET_DOUBLE_VAL(&pAgg->max);
      } else if (IS_UNSIGNED_NUMERIC_TYPE(type)) {
        tmin = (double)GET_UINT64_VAL(&pAgg->min);
        tmax = (double)GET_UINT64_VAL(&pAgg->max);
H
Haojun Liao 已提交
924 925 926 927 928 929 930 931 932 933
      }

      if (GET_DOUBLE_VAL(&pInfo->minval) > tmin) {
        SET_DOUBLE_VAL(&pInfo->minval, tmin);
      }

      if (GET_DOUBLE_VAL(&pInfo->maxval) < tmax) {
        SET_DOUBLE_VAL(&pInfo->maxval, tmax);
      }

934
      pInfo->numOfElems += (pInput->numOfRows - pAgg->numOfNull);
H
Haojun Liao 已提交
935
    } else {
936 937 938 939
      // check the valid data one by one
      int32_t start = pInput->startRowIndex;
      for (int32_t i = start; i < pInput->numOfRows + start; ++i) {
        if (colDataIsNull_f(pCol->nullbitmap, i)) {
H
Haojun Liao 已提交
940 941 942
          continue;
        }

943
        char* data = colDataGetData(pCol, i);
944

H
Haojun Liao 已提交
945 946 947 948 949 950 951 952 953 954 955 956 957 958
        double v = 0;
        GET_TYPED_DATA(v, double, pCtx->inputType, data);
        if (v < GET_DOUBLE_VAL(&pInfo->minval)) {
          SET_DOUBLE_VAL(&pInfo->minval, v);
        }

        if (v > GET_DOUBLE_VAL(&pInfo->maxval)) {
          SET_DOUBLE_VAL(&pInfo->maxval, v);
        }

        pInfo->numOfElems += 1;
      }
    }

H
Haojun Liao 已提交
959
    return 0;
H
Haojun Liao 已提交
960 961 962
  }

  // the second stage, calculate the true percentile value
963 964 965
  int32_t start = pInput->startRowIndex;
  for (int32_t i = start; i < pInput->numOfRows + start; ++i) {
    if (colDataIsNull_f(pCol->nullbitmap, i)) {
H
Haojun Liao 已提交
966 967 968
      continue;
    }

969
    char* data = colDataGetData(pCol, i);
970

H
Haojun Liao 已提交
971 972 973 974
    notNullElems += 1;
    tMemBucketPut(pInfo->pMemBucket, data, 1);
  }

975
  SET_VAL(pResInfo, notNullElems, 1);
wmmhello's avatar
wmmhello 已提交
976
  return TSDB_CODE_SUCCESS;
977 978
}

979
int32_t percentileFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
980
  SVariant* pVal = &pCtx->param[1].param;
981
  double    v = pVal->nType == TSDB_DATA_TYPE_INT ? pVal->i : pVal->d;
H
Haojun Liao 已提交
982

983 984
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
  SPercentileInfo*     ppInfo = (SPercentileInfo*)GET_ROWCELL_INTERBUF(pResInfo);
985

986
  tMemBucket* pMemBucket = ppInfo->pMemBucket;
987 988 989 990 991
  if (pMemBucket != NULL && pMemBucket->total > 0) {  // check for null
    SET_DOUBLE_VAL(&ppInfo->result, getPercentile(pMemBucket, v));
  }

  tMemBucketDestroy(pMemBucket);
992
  return functionFinalize(pCtx, pBlock);
H
Haojun Liao 已提交
993
}
H
Haojun Liao 已提交
994

H
Haojun Liao 已提交
995 996
bool getFirstLastFuncEnv(SFunctionNode* pFunc, SFuncExecEnv* pEnv) {
  SColumnNode* pNode = nodesListGetNode(pFunc->pParameterList, 0);
997
  pEnv->calcMemSize = pNode->node.resType.bytes + sizeof(int64_t);
H
Haojun Liao 已提交
998 999 1000
  return true;
}

1001 1002 1003 1004 1005
static FORCE_INLINE TSKEY getRowPTs(SColumnInfoData* pTsColInfo, int32_t rowIndex) {
  if (pTsColInfo == NULL) {
    return 0;
  }

1006
  return *(TSKEY*)colDataGetData(pTsColInfo, rowIndex);
1007 1008
}

1009 1010
// This ordinary first function does not care if current scan is ascending order or descending order scan
// the OPTIMIZED version of first function will only handle the ascending order scan
1011
int32_t firstFunction(SqlFunctionCtx* pCtx) {
H
Haojun Liao 已提交
1012 1013
  int32_t numOfElems = 0;

1014 1015
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
  char*                buf = GET_ROWCELL_INTERBUF(pResInfo);
H
Haojun Liao 已提交
1016 1017

  SInputColumnInfoData* pInput = &pCtx->input;
1018
  SColumnInfoData*      pInputCol = pInput->pData[0];
H
Haojun Liao 已提交
1019

1020 1021
  int32_t bytes = pInputCol->info.bytes;

H
Haojun Liao 已提交
1022
  // All null data column, return directly.
H
Haojun Liao 已提交
1023
  if (pInput->colDataAggIsSet && (pInput->pColumnDataAgg[0]->numOfNull == pInput->totalRows)) {
H
Haojun Liao 已提交
1024
    ASSERT(pInputCol->hasNull == true);
H
Haojun Liao 已提交
1025
    return 0;
H
Haojun Liao 已提交
1026 1027
  }

1028
  SColumnDataAgg* pColAgg = (pInput->colDataAggIsSet) ? pInput->pColumnDataAgg[0] : NULL;
1029

1030 1031
  TSKEY startKey = getRowPTs(pInput->pPTS, 0);
  TSKEY endKey = getRowPTs(pInput->pPTS, pInput->totalRows - 1);
1032

1033
  int32_t blockDataOrder = (startKey <= endKey) ? TSDB_ORDER_ASC : TSDB_ORDER_DESC;
1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048

  if (blockDataOrder == TSDB_ORDER_ASC) {
    // filter according to current result firstly
    if (pResInfo->numOfRes > 0) {
      TSKEY ts = *(TSKEY*)(buf + bytes);
      if (ts < startKey) {
        return TSDB_CODE_SUCCESS;
      }
    }

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

1049 1050
      numOfElems++;

1051
      char* data = colDataGetData(pInputCol, i);
1052
      TSKEY cts = getRowPTs(pInput->pPTS, i);
1053

1054
      if (pResInfo->numOfRes == 0 || *(TSKEY*)(buf + bytes) > cts) {
1055 1056
        memcpy(buf, data, bytes);
        *(TSKEY*)(buf + bytes) = cts;
1057
        //        DO_UPDATE_TAG_COLUMNS(pCtx, ts);
1058 1059

        pResInfo->numOfRes = 1;
1060
        break;
1061 1062 1063 1064 1065 1066 1067 1068 1069 1070
      }
    }
  } else {
    // in case of descending order time stamp serial, which usually happens as the results of the nest query,
    // all data needs to be check.
    if (pResInfo->numOfRes > 0) {
      TSKEY ts = *(TSKEY*)(buf + bytes);
      if (ts < endKey) {
        return TSDB_CODE_SUCCESS;
      }
H
Haojun Liao 已提交
1071 1072
    }

1073 1074 1075 1076 1077
    for (int32_t i = pInput->numOfRows + pInput->startRowIndex - 1; i >= pInput->startRowIndex; --i) {
      if (pInputCol->hasNull && colDataIsNull(pInputCol, pInput->totalRows, i, pColAgg)) {
        continue;
      }

1078 1079
      numOfElems++;

1080
      char* data = colDataGetData(pInputCol, i);
1081
      TSKEY cts = getRowPTs(pInput->pPTS, i);
1082

1083
      if (pResInfo->numOfRes == 0 || *(TSKEY*)(buf + bytes) > cts) {
1084 1085
        memcpy(buf, data, bytes);
        *(TSKEY*)(buf + bytes) = cts;
1086
        //        DO_UPDATE_TAG_COLUMNS(pCtx, ts);
1087
        pResInfo->numOfRes = 1;
1088
        break;
1089 1090
      }
    }
H
Haojun Liao 已提交
1091 1092 1093
  }

  SET_VAL(pResInfo, numOfElems, 1);
wmmhello's avatar
wmmhello 已提交
1094
  return TSDB_CODE_SUCCESS;
H
Haojun Liao 已提交
1095 1096
}

1097
int32_t lastFunction(SqlFunctionCtx* pCtx) {
H
Haojun Liao 已提交
1098 1099
  int32_t numOfElems = 0;

1100 1101
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
  char*                buf = GET_ROWCELL_INTERBUF(pResInfo);
H
Haojun Liao 已提交
1102 1103

  SInputColumnInfoData* pInput = &pCtx->input;
1104
  SColumnInfoData*      pInputCol = pInput->pData[0];
H
Haojun Liao 已提交
1105

1106 1107
  int32_t bytes = pInputCol->info.bytes;

H
Haojun Liao 已提交
1108
  // All null data column, return directly.
1109
  if (pInput->colDataAggIsSet && (pInput->pColumnDataAgg[0]->numOfNull == pInput->totalRows)) {
H
Haojun Liao 已提交
1110
    ASSERT(pInputCol->hasNull == true);
H
Haojun Liao 已提交
1111
    return 0;
H
Haojun Liao 已提交
1112 1113
  }

1114
  SColumnDataAgg* pColAgg = (pInput->colDataAggIsSet) ? pInput->pColumnDataAgg[0] : NULL;
1115 1116 1117 1118

  TSKEY startKey = getRowPTs(pInput->pPTS, 0);
  TSKEY endKey = getRowPTs(pInput->pPTS, pInput->totalRows - 1);

1119
  int32_t blockDataOrder = (startKey <= endKey) ? TSDB_ORDER_ASC : TSDB_ORDER_DESC;
1120 1121

  if (blockDataOrder == TSDB_ORDER_ASC) {
H
Haojun Liao 已提交
1122
    for (int32_t i = pInput->numOfRows + pInput->startRowIndex - 1; i >= pInput->startRowIndex; --i) {
1123
      if (pInputCol->hasNull && colDataIsNull(pInputCol, pInput->totalRows, i, pColAgg)) {
H
Haojun Liao 已提交
1124 1125 1126 1127
        continue;
      }

      numOfElems++;
1128 1129 1130

      char* data = colDataGetData(pInputCol, i);
      TSKEY cts = getRowPTs(pInput->pPTS, i);
1131
      if (pResInfo->numOfRes == 0 || *(TSKEY*)(buf + bytes) < cts) {
1132 1133 1134 1135 1136
        memcpy(buf, data, bytes);
        *(TSKEY*)(buf + bytes) = cts;
        //        DO_UPDATE_TAG_COLUMNS(pCtx, ts);
        pResInfo->numOfRes = 1;
      }
H
Haojun Liao 已提交
1137 1138
      break;
    }
1139
  } else {  // descending order
H
Haojun Liao 已提交
1140
    for (int32_t i = pInput->startRowIndex; i < pInput->numOfRows + pInput->startRowIndex; ++i) {
1141
      if (pInputCol->hasNull && colDataIsNull(pInputCol, pInput->totalRows, i, pColAgg)) {
H
Haojun Liao 已提交
1142 1143 1144
        continue;
      }

1145
      numOfElems++;
H
Haojun Liao 已提交
1146

1147 1148
      char* data = colDataGetData(pInputCol, i);
      TSKEY cts = getRowPTs(pInput->pPTS, i);
1149
      if (pResInfo->numOfRes == 0 || *(TSKEY*)(buf + bytes) < cts) {
1150 1151 1152
        memcpy(buf, data, bytes);
        *(TSKEY*)(buf + bytes) = cts;
        pResInfo->numOfRes = 1;
1153
        //        DO_UPDATE_TAG_COLUMNS(pCtx, ts);
H
Haojun Liao 已提交
1154 1155 1156 1157 1158 1159
      }
      break;
    }
  }

  SET_VAL(pResInfo, numOfElems, 1);
wmmhello's avatar
wmmhello 已提交
1160
  return TSDB_CODE_SUCCESS;
H
Haojun Liao 已提交
1161
}
H
Haojun Liao 已提交
1162

H
Haojun Liao 已提交
1163 1164 1165 1166 1167
bool getDiffFuncEnv(SFunctionNode* UNUSED_PARAM(pFunc), SFuncExecEnv* pEnv) {
  pEnv->calcMemSize = sizeof(SDiffInfo);
  return true;
}

1168
bool diffFunctionSetup(SqlFunctionCtx* pCtx, SResultRowEntryInfo* pResInfo) {
H
Haojun Liao 已提交
1169 1170 1171 1172 1173
  if (!functionSetup(pCtx, pResInfo)) {
    return false;
  }

  SDiffInfo* pDiffInfo = GET_ROWCELL_INTERBUF(pResInfo);
1174
  pDiffInfo->hasPrev = false;
H
Haojun Liao 已提交
1175
  pDiffInfo->prev.i64 = 0;
1176
  pDiffInfo->ignoreNegative = false;  // TODO set correct param
H
Haojun Liao 已提交
1177 1178
  pDiffInfo->includeNull = false;
  pDiffInfo->firstOutput = false;
H
Haojun Liao 已提交
1179 1180 1181
  return true;
}

1182 1183 1184
int32_t diffFunction(SqlFunctionCtx* pCtx) {
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
  SDiffInfo*           pDiffInfo = GET_ROWCELL_INTERBUF(pResInfo);
H
Haojun Liao 已提交
1185 1186

  SInputColumnInfoData* pInput = &pCtx->input;
1187
  SColumnInfoData*      pInputCol = pInput->pData[0];
H
Haojun Liao 已提交
1188

1189
  bool    isFirstBlock = (pDiffInfo->hasPrev == false);
H
Haojun Liao 已提交
1190 1191 1192
  int32_t numOfElems = 0;

  int32_t step = GET_FORWARD_DIRECTION_FACTOR(pCtx->order);
1193
  //  int32_t i = (pCtx->order == TSDB_ORDER_ASC) ? 0 : pCtx->size - 1;
H
Haojun Liao 已提交
1194

H
Haojun Liao 已提交
1195
  SColumnInfoData* pTsOutput = pCtx->pTsOutput;
1196
  TSKEY*           tsList = (int64_t*)pInput->pPTS->pData;
H
Haojun Liao 已提交
1197

H
Haojun Liao 已提交
1198
  int32_t startOffset = pCtx->offset;
H
Haojun Liao 已提交
1199 1200
  switch (pInputCol->info.type) {
    case TSDB_DATA_TYPE_INT: {
1201
      SColumnInfoData* pOutput = (SColumnInfoData*)pCtx->pOutput;
H
Haojun Liao 已提交
1202
      for (int32_t i = pInput->startRowIndex; i < pInput->numOfRows + pInput->startRowIndex; i += step) {
1203
        int32_t pos = startOffset + (isFirstBlock ? (numOfElems - 1) : numOfElems);
H
Haojun Liao 已提交
1204
        if (colDataIsNull_f(pInputCol->nullbitmap, i)) {
H
Haojun Liao 已提交
1205 1206 1207 1208 1209 1210 1211 1212
          if (pDiffInfo->includeNull) {
            colDataSetNull_f(pOutput->nullbitmap, pos);
            if (tsList != NULL) {
              colDataAppendInt64(pTsOutput, pos, &tsList[i]);
            }

            numOfElems += 1;
          }
H
Haojun Liao 已提交
1213 1214 1215
          continue;
        }

1216
        int32_t v = *(int32_t*)colDataGetData(pInputCol, i);
H
Haojun Liao 已提交
1217 1218 1219 1220 1221 1222
        if (pDiffInfo->hasPrev) {
          int32_t delta = (int32_t)(v - pDiffInfo->prev.i64);  // direct previous may be null
          if (delta < 0 && pDiffInfo->ignoreNegative) {
            colDataSetNull_f(pOutput->nullbitmap, pos);
          } else {
            colDataAppendInt32(pOutput, pos, &delta);
H
Haojun Liao 已提交
1223 1224
          }

1225
          if (pTsOutput != NULL) {
H
Haojun Liao 已提交
1226 1227
            colDataAppendInt64(pTsOutput, pos, &tsList[i]);
          }
H
Haojun Liao 已提交
1228 1229 1230
        }

        pDiffInfo->prev.i64 = v;
1231
        pDiffInfo->hasPrev = true;
H
Haojun Liao 已提交
1232 1233 1234 1235
        numOfElems++;
      }
      break;
    }
H
Haojun Liao 已提交
1236

H
Haojun Liao 已提交
1237
    case TSDB_DATA_TYPE_BIGINT: {
1238
      SColumnInfoData* pOutput = (SColumnInfoData*)pCtx->pOutput;
H
Haojun Liao 已提交
1239 1240 1241 1242 1243 1244
      for (int32_t i = pInput->startRowIndex; i < pInput->numOfRows + pInput->startRowIndex; i += step) {
        if (colDataIsNull_f(pInputCol->nullbitmap, i)) {
          continue;
        }

        int32_t v = 0;
H
Haojun Liao 已提交
1245
        if (pDiffInfo->hasPrev) {
1246
          v = *(int64_t*)colDataGetData(pInputCol, i);
H
Haojun Liao 已提交
1247 1248 1249 1250 1251
          int64_t delta = (int64_t)(v - pDiffInfo->prev.i64);  // direct previous may be null
          if (pDiffInfo->ignoreNegative) {
            continue;
          }

1252 1253 1254 1255 1256
          //          *(pOutput++) = delta;
          //          *pTimestamp  = (tsList != NULL)? tsList[i]:0;
          //
          //          pOutput    += 1;
          //          pTimestamp += 1;
H
Haojun Liao 已提交
1257 1258 1259
        }

        pDiffInfo->prev.i64 = v;
H
Haojun Liao 已提交
1260
        pDiffInfo->hasPrev = true;
H
Haojun Liao 已提交
1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276
        numOfElems++;
      }
      break;
    }
#if 0
    case TSDB_DATA_TYPE_DOUBLE: {
      double *pData = (double *)data;
      double *pOutput = (double *)pCtx->pOutput;

      for (; i < pCtx->size && i >= 0; i += step) {
        if (pCtx->hasNull && isNull((const char*) &pData[i], pCtx->inputType)) {
          continue;
        }
        if ((pDiffInfo->ignoreNegative) && (pData[i] < 0)) {
          continue;
        }
H
Haojun Liao 已提交
1277

H
Haojun Liao 已提交
1278
        if (pDiffInfo->hasPrev) {  // initial value is not set yet
H
Haojun Liao 已提交
1279 1280 1281 1282 1283 1284 1285
          SET_DOUBLE_VAL(pOutput, pData[i] - pDiffInfo->d64Prev);  // direct previous may be null
          *pTimestamp = (tsList != NULL)? tsList[i]:0;
          pOutput    += 1;
          pTimestamp += 1;
        }

        pDiffInfo->d64Prev = pData[i];
H
Haojun Liao 已提交
1286
        pDiffInfo->hasPrev = true;
H
Haojun Liao 已提交
1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302
        numOfElems++;
      }
      break;
    }
    case TSDB_DATA_TYPE_FLOAT: {
      float *pData = (float *)data;
      float *pOutput = (float *)pCtx->pOutput;

      for (; i < pCtx->size && i >= 0; i += step) {
        if (pCtx->hasNull && isNull((const char*) &pData[i], pCtx->inputType)) {
          continue;
        }
        if ((pDiffInfo->ignoreNegative) && (pData[i] < 0)) {
          continue;
        }

H
Haojun Liao 已提交
1303
        if (pDiffInfo->hasPrev) {  // initial value is not set yet
H
Haojun Liao 已提交
1304 1305 1306 1307 1308 1309 1310
          *pOutput = (float)(pData[i] - pDiffInfo->d64Prev);  // direct previous may be null
          *pTimestamp = (tsList != NULL)? tsList[i]:0;
          pOutput    += 1;
          pTimestamp += 1;
        }

        pDiffInfo->d64Prev = pData[i];
H
Haojun Liao 已提交
1311
        pDiffInfo->hasPrev = true;
H
Haojun Liao 已提交
1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327
        numOfElems++;
      }
      break;
    }
    case TSDB_DATA_TYPE_SMALLINT: {
      int16_t *pData = (int16_t *)data;
      int16_t *pOutput = (int16_t *)pCtx->pOutput;

      for (; i < pCtx->size && i >= 0; i += step) {
        if (pCtx->hasNull && isNull((const char*) &pData[i], pCtx->inputType)) {
          continue;
        }
        if ((pDiffInfo->ignoreNegative) && (pData[i] < 0)) {
          continue;
        }

H
Haojun Liao 已提交
1328
        if (pDiffInfo->hasPrev) {  // initial value is not set yet
H
Haojun Liao 已提交
1329 1330 1331 1332 1333 1334 1335
          *pOutput = (int16_t)(pData[i] - pDiffInfo->i64Prev);  // direct previous may be null
          *pTimestamp = (tsList != NULL)? tsList[i]:0;
          pOutput    += 1;
          pTimestamp += 1;
        }

        pDiffInfo->i64Prev = pData[i];
H
Haojun Liao 已提交
1336
        pDiffInfo->hasPrev = true;
H
Haojun Liao 已提交
1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353
        numOfElems++;
      }
      break;
    }

    case TSDB_DATA_TYPE_TINYINT: {
      int8_t *pData = (int8_t *)data;
      int8_t *pOutput = (int8_t *)pCtx->pOutput;

      for (; i < pCtx->size && i >= 0; i += step) {
        if (pCtx->hasNull && isNull((char *)&pData[i], pCtx->inputType)) {
          continue;
        }
        if ((pDiffInfo->ignoreNegative) && (pData[i] < 0)) {
          continue;
        }

H
Haojun Liao 已提交
1354
        if (pDiffInfo->hasPrev) {  // initial value is not set yet
H
Haojun Liao 已提交
1355 1356 1357 1358 1359 1360 1361
          *pOutput = (int8_t)(pData[i] - pDiffInfo->i64Prev);  // direct previous may be null
          *pTimestamp = (tsList != NULL)? tsList[i]:0;
          pOutput    += 1;
          pTimestamp += 1;
        }

        pDiffInfo->i64Prev = pData[i];
H
Haojun Liao 已提交
1362
        pDiffInfo->hasPrev = true;
H
Haojun Liao 已提交
1363 1364 1365 1366 1367 1368 1369
        numOfElems++;
      }
      break;
    }
#endif
    default:
      break;
1370
      //      qError("error input type");
H
Haojun Liao 已提交
1371 1372 1373
  }

  // initial value is not set yet
H
Haojun Liao 已提交
1374
  if (!pDiffInfo->hasPrev || numOfElems <= 0) {
H
Haojun Liao 已提交
1375 1376 1377 1378 1379
    /*
     * 1. current block and blocks before are full of null
     * 2. current block may be null value
     */
    assert(pCtx->hasNull);
wmmhello's avatar
wmmhello 已提交
1380
    return 0;
H
Haojun Liao 已提交
1381
  } else {
1382 1383 1384 1385 1386 1387
    //    for (int t = 0; t < pCtx->tagInfo.numOfTagCols; ++t) {
    //      SqlFunctionCtx* tagCtx = pCtx->tagInfo.pTagCtxList[t];
    //      if (tagCtx->functionId == TSDB_FUNC_TAG_DUMMY) {
    //        aAggs[TSDB_FUNC_TAGPRJ].xFunction(tagCtx);
    //      }
    //    }
H
Haojun Liao 已提交
1388 1389 1390 1391

    int32_t forwardStep = (isFirstBlock) ? numOfElems - 1 : numOfElems;
    return forwardStep;
  }
H
Haojun Liao 已提交
1392
}
H
Haojun Liao 已提交
1393

1394
bool getTopBotFuncEnv(SFunctionNode* pFunc, SFuncExecEnv* pEnv) {
1395
  SValueNode* pkNode = (SValueNode*)nodesListGetNode(pFunc->pParameterList, 1);
1396
  pEnv->calcMemSize = sizeof(STopBotRes) + pkNode->datum.i * sizeof(STopBotResItem);
1397 1398 1399
  return true;
}

1400 1401 1402 1403
static STopBotRes* getTopBotOutputInfo(SqlFunctionCtx* pCtx) {
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
  STopBotRes*          pRes = GET_ROWCELL_INTERBUF(pResInfo);
  pRes->pItems = (STopBotResItem*)((char*)pRes + sizeof(STopBotRes));
1404 1405

  return pRes;
1406 1407
}

1408 1409
static void doAddIntoResult(SqlFunctionCtx* pCtx, void* pData, int32_t rowIndex, SSDataBlock* pSrcBlock, uint16_t type,
                            uint64_t uid, SResultRowEntryInfo* pEntryInfo);
1410

1411 1412 1413
static void saveTupleData(SqlFunctionCtx* pCtx, int32_t rowIndex, const SSDataBlock* pSrcBlock, STopBotResItem* pItem);
static void copyTupleData(SqlFunctionCtx* pCtx, int32_t rowIndex, const SSDataBlock* pSrcBlock, STopBotResItem* pItem);

1414 1415 1416
int32_t topFunction(SqlFunctionCtx* pCtx) {
  int32_t              numOfElems = 0;
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
1417

1418 1419 1420
  //  if ((void *)pRes->res[0] != (void *)((char *)pRes + sizeof(STopBotRes) + POINTER_BYTES * pCtx->param[0].i)) {
  //    buildTopBotStruct(pRes, pCtx);
  //  }
1421 1422

  SInputColumnInfoData* pInput = &pCtx->input;
1423
  SColumnInfoData*      pCol = pInput->pData[0];
1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436

  int32_t type = pInput->pData[0]->info.type;

  int32_t start = pInput->startRowIndex;
  int32_t numOfRows = pInput->numOfRows;

  for (int32_t i = start; i < numOfRows + start; ++i) {
    if (pCol->hasNull && colDataIsNull_f(pCol->nullbitmap, i)) {
      continue;
    }
    numOfElems++;

    char* data = colDataGetData(pCol, i);
1437
    doAddIntoResult(pCtx, data, i, pCtx->pSrcBlock, type, pInput->uid, pResInfo);
1438 1439
  }

1440
  return TSDB_CODE_SUCCESS;
1441 1442
}

1443 1444
static int32_t topBotResComparFn(const void* p1, const void* p2, const void* param) {
  uint16_t type = *(uint16_t*)param;
1445

1446 1447
  STopBotResItem* val1 = (STopBotResItem*)p1;
  STopBotResItem* val2 = (STopBotResItem*)p2;
1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469

  if (IS_SIGNED_NUMERIC_TYPE(type)) {
    if (val1->v.i == val2->v.i) {
      return 0;
    }

    return (val1->v.i > val2->v.i) ? 1 : -1;
  } else if (IS_UNSIGNED_NUMERIC_TYPE(type)) {
    if (val1->v.u == val2->v.u) {
      return 0;
    }

    return (val1->v.u > val2->v.u) ? 1 : -1;
  }

  if (val1->v.d == val2->v.d) {
    return 0;
  }

  return (val1->v.d > val2->v.d) ? 1 : -1;
}

1470 1471
void doAddIntoResult(SqlFunctionCtx* pCtx, void* pData, int32_t rowIndex, SSDataBlock* pSrcBlock, uint16_t type,
                     uint64_t uid, SResultRowEntryInfo* pEntryInfo) {
1472 1473
  STopBotRes* pRes = getTopBotOutputInfo(pCtx);
  int32_t     maxSize = pCtx->param[1].param.i;
1474

1475 1476 1477
  SVariant val = {0};
  taosVariantCreateFromBinary(&val, pData, tDataTypes[type].bytes, type);

1478
  STopBotResItem* pItems = pRes->pItems;
1479 1480 1481
  assert(pItems != NULL);

  // not full yet
1482 1483
  if (pEntryInfo->numOfRes < maxSize) {
    STopBotResItem* pItem = &pItems[pEntryInfo->numOfRes];
1484
    pItem->v = val;
1485
    pItem->uid = uid;
1486

1487 1488
    // save the data of this tuple
    saveTupleData(pCtx, rowIndex, pSrcBlock, pItem);
1489 1490 1491

    // allocate the buffer and keep the data of this row into the new allocated buffer
    pEntryInfo->numOfRes++;
1492 1493 1494
    taosheapsort((void*)pItems, sizeof(STopBotResItem), pEntryInfo->numOfRes, (const void*)&type, topBotResComparFn,
                 false);
  } else {  // replace the minimum value in the result
1495
    if ((IS_SIGNED_NUMERIC_TYPE(type) && val.i > pItems[0].v.i) ||
1496
        (IS_UNSIGNED_NUMERIC_TYPE(type) && val.u > pItems[0].v.u) || (IS_FLOAT_TYPE(type) && val.d > pItems[0].v.d)) {
1497
      // replace the old data and the coresponding tuple data
1498
      STopBotResItem* pItem = &pItems[0];
1499
      pItem->v = val;
1500
      pItem->uid = uid;
1501 1502 1503

      // save the data of this tuple by over writing the old data
      copyTupleData(pCtx, rowIndex, pSrcBlock, pItem);
1504

1505 1506
      taosheapadjust((void*)pItems, sizeof(STopBotResItem), 0, pEntryInfo->numOfRes - 1, (const void*)&type,
                     topBotResComparFn, NULL, false);
1507
    }
1508 1509
  }
}
1510

1511 1512 1513 1514 1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525 1526 1527 1528 1529 1530 1531 1532 1533 1534 1535 1536 1537 1538 1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563 1564
void saveTupleData(SqlFunctionCtx* pCtx, int32_t rowIndex, const SSDataBlock* pSrcBlock, STopBotResItem* pItem) {
  SFilePage* pPage = NULL;

  int32_t completeRowSize = pSrcBlock->info.rowSize + pSrcBlock->info.numOfCols * sizeof(bool);

  if (pCtx->curBufPage == -1) {
    pPage = getNewBufPage(pCtx->pBuf, 0, &pCtx->curBufPage);
    pPage->num = sizeof(SFilePage);
  } else {
    pPage = getBufPage(pCtx->pBuf, pCtx->curBufPage);
    if (pPage->num + completeRowSize > getBufPageSize(pCtx->pBuf)) {
      pPage = getNewBufPage(pCtx->pBuf, 0, &pCtx->curBufPage);
      pPage->num = sizeof(SFilePage);
    }
  }

  pItem->tuplePos.pageId = pCtx->curBufPage;

  // keep the current row data, extract method
  int32_t offset = 0;
  bool*   nullList = (bool*)((char*)pPage + pPage->num);
  char*   pStart = (char*)(nullList + sizeof(bool) * pSrcBlock->info.numOfCols);
  for (int32_t i = 0; i < pSrcBlock->info.numOfCols; ++i) {
    SColumnInfoData* pCol = taosArrayGet(pSrcBlock->pDataBlock, i);
    bool             isNull = colDataIsNull_s(pCol, rowIndex);
    if (isNull) {
      nullList[i] = true;
      continue;
    }

    char* p = colDataGetData(pCol, rowIndex);
    if (IS_VAR_DATA_TYPE(pCol->info.type)) {
      memcpy(pStart + offset, p, varDataTLen(p));
    } else {
      memcpy(pStart + offset, p, pCol->info.bytes);
    }

    offset += pCol->info.bytes;
  }

  pItem->tuplePos.offset = pPage->num;
  pPage->num += completeRowSize;

  setBufPageDirty(pPage, true);
  releaseBufPage(pCtx->pBuf, pPage);
}

void copyTupleData(SqlFunctionCtx* pCtx, int32_t rowIndex, const SSDataBlock* pSrcBlock, STopBotResItem* pItem) {
  SFilePage* pPage = getBufPage(pCtx->pBuf, pItem->tuplePos.pageId);

  bool* nullList = (bool*)((char*)pPage + pItem->tuplePos.offset);
  char* pStart = (char*)(nullList + pSrcBlock->info.numOfCols * sizeof(bool));

  int32_t offset = 0;
1565
  for (int32_t i = 0; i < pSrcBlock->info.numOfCols; ++i) {
1566 1567 1568 1569 1570 1571 1572 1573 1574 1575 1576 1577 1578 1579 1580 1581 1582 1583 1584 1585
    SColumnInfoData* pCol = taosArrayGet(pSrcBlock->pDataBlock, i);
    if ((nullList[i] = colDataIsNull_s(pCol, rowIndex)) == true) {
      continue;
    }

    char* p = colDataGetData(pCol, rowIndex);
    if (IS_VAR_DATA_TYPE(pCol->info.type)) {
      memcpy(pStart + offset, p, varDataTLen(p));
    } else {
      memcpy(pStart + offset, p, pCol->info.bytes);
    }

    offset += pCol->info.bytes;
  }

  setBufPageDirty(pPage, true);
  releaseBufPage(pCtx->pBuf, pPage);
}

int32_t topBotFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
1586 1587
  SResultRowEntryInfo* pEntryInfo = GET_RES_INFO(pCtx);
  STopBotRes*          pRes = GET_ROWCELL_INTERBUF(pEntryInfo);
1588 1589
  pEntryInfo->complete = true;

1590 1591
  int32_t          type = pCtx->input.pData[0]->info.type;
  int32_t          slotId = pCtx->pExpr->base.resSchema.slotId;
1592 1593 1594 1595
  SColumnInfoData* pCol = taosArrayGet(pBlock->pDataBlock, slotId);

  // todo assign the tag value and the corresponding row data
  int32_t currentRow = pBlock->info.rows;
1596
  switch (type) {
1597 1598 1599
    case TSDB_DATA_TYPE_INT: {
      for (int32_t i = 0; i < pEntryInfo->numOfRes; ++i) {
        STopBotResItem* pItem = &pRes->pItems[i];
1600
        colDataAppendInt32(pCol, currentRow, (int32_t*)&pItem->v.i);
1601 1602 1603

        int32_t pageId = pItem->tuplePos.pageId;
        int32_t offset = pItem->tuplePos.offset;
1604 1605
        if (pItem->tuplePos.pageId != -1) {
          SFilePage* pPage = getBufPage(pCtx->pBuf, pageId);
H
Haojun Liao 已提交
1606

1607 1608 1609 1610 1611 1612 1613
          bool* nullList = (bool*)((char*)pPage + offset);
          char* pStart = (char*)(nullList + pCtx->pSrcBlock->info.numOfCols * sizeof(bool));

          // todo set the offset value to optimize the performance.
          for (int32_t j = 0; j < pCtx->subsidiaries.num; ++j) {
            SqlFunctionCtx* pc = pCtx->subsidiaries.pCtx[j];

1614 1615 1616
            SFunctParam* pFuncParam = &pc->pExpr->base.pParam[0];
            int32_t      srcSlotId = pFuncParam->pCol->slotId;
            int32_t      dstSlotId = pCtx->pExpr->base.resSchema.slotId;
1617 1618

            int32_t ps = 0;
1619
            for (int32_t k = 0; k < srcSlotId; ++k) {
1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 1630
              SColumnInfoData* pSrcCol = taosArrayGet(pCtx->pSrcBlock->pDataBlock, k);
              ps += pSrcCol->info.bytes;
            }

            SColumnInfoData* pDstCol = taosArrayGet(pBlock->pDataBlock, dstSlotId);
            if (nullList[srcSlotId]) {
              colDataAppendNULL(pDstCol, currentRow);
            } else {
              colDataAppend(pDstCol, currentRow, (pStart + ps), false);
            }
          }
1631
        }
1632 1633

        currentRow += 1;
1634
      }
H
Haojun Liao 已提交
1635

1636 1637 1638 1639 1640
      break;
    }
  }

  return pEntryInfo->numOfRes;
1641
}