groupoperator.c 42.3 KB
Newer Older
H
Haojun Liao 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
/*
 * 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/>.
 */

16
#include "filter.h"
H
Haojun Liao 已提交
17
#include "function.h"
18
#include "os.h"
H
Haojun Liao 已提交
19 20 21 22 23
#include "tname.h"

#include "tdatablock.h"
#include "tmsg.h"

24
#include "executorInt.h"
H
Haojun Liao 已提交
25 26 27 28 29
#include "executorimpl.h"
#include "tcompare.h"
#include "thash.h"
#include "ttypes.h"

H
Haojun Liao 已提交
30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59
typedef struct SGroupbyOperatorInfo {
  SOptrBasicInfo binfo;
  SAggSupporter  aggSup;
  SArray*        pGroupCols;     // group by columns, SArray<SColumn>
  SArray*        pGroupColVals;  // current group column values, SArray<SGroupKeys>
  bool           isInit;         // denote if current val is initialized or not
  char*          keyBuf;         // group by keys for hash
  int32_t        groupKeyLen;    // total group by column width
  SGroupResInfo  groupResInfo;
  SExprSupp      scalarSup;
} SGroupbyOperatorInfo;

// The sort in partition may be needed later.
typedef struct SPartitionOperatorInfo {
  SOptrBasicInfo binfo;
  SArray*        pGroupCols;
  SArray*        pGroupColVals;  // current group column values, SArray<SGroupKeys>
  char*          keyBuf;         // group by keys for hash
  int32_t        groupKeyLen;    // total group by column width
  SHashObj*      pGroupSet;      // quick locate the window object for each result

  SDiskbasedBuf* pBuf;              // query result buffer based on blocked-wised disk file
  int32_t        rowCapacity;       // maximum number of rows for each buffer page
  int32_t*       columnOffset;      // start position for each column data
  SArray*        sortedGroupArray;  // SDataGroupInfo sorted by group id
  int32_t        groupIndex;        // group index
  int32_t        pageIndex;         // page index of current group
  SExprSupp      scalarSup;
} SPartitionOperatorInfo;

60
static void*    getCurrentDataGroupInfo(const SPartitionOperatorInfo* pInfo, SDataGroupInfo** pGroupInfo, int32_t len);
H
Haojun Liao 已提交
61
static int32_t* setupColumnOffset(const SSDataBlock* pBlock, int32_t rowCapacity);
62 63
static int32_t  setGroupResultOutputBuf(SOperatorInfo* pOperator, SOptrBasicInfo* binfo, int32_t numOfCols, char* pData,
                                        int16_t bytes, uint64_t groupId, SDiskbasedBuf* pBuf, SAggSupporter* pAggSup);
H
Haojun Liao 已提交
64
static SArray*  extractColumnInfo(SNodeList* pNodeList);
H
Haojun Liao 已提交
65

H
Haojun Liao 已提交
66
static void freeGroupKey(void* param) {
67
  SGroupKeys* pKey = (SGroupKeys*)param;
H
Haojun Liao 已提交
68 69 70
  taosMemoryFree(pKey->pData);
}

71
static void destroyGroupOperatorInfo(void* param) {
H
Haojun Liao 已提交
72
  SGroupbyOperatorInfo* pInfo = (SGroupbyOperatorInfo*)param;
73 74 75 76
  if (pInfo == NULL) {
    return;
  }

77
  cleanupBasicInfo(&pInfo->binfo);
H
Haojun Liao 已提交
78 79
  taosMemoryFreeClear(pInfo->keyBuf);
  taosArrayDestroy(pInfo->pGroupCols);
H
Haojun Liao 已提交
80
  taosArrayDestroyEx(pInfo->pGroupColVals, freeGroupKey);
81
  cleanupExprSupp(&pInfo->scalarSup);
H
Haojun Liao 已提交
82 83 84

  cleanupGroupResInfo(&pInfo->groupResInfo);
  cleanupAggSup(&pInfo->aggSup);
D
dapan1121 已提交
85
  taosMemoryFreeClear(param);
H
Haojun Liao 已提交
86 87
}

wmmhello's avatar
wmmhello 已提交
88
static int32_t initGroupOptrInfo(SArray** pGroupColVals, int32_t* keyLen, char** keyBuf, const SArray* pGroupColList) {
H
Haojun Liao 已提交
89 90
  *pGroupColVals = taosArrayInit(4, sizeof(SGroupKeys));
  if ((*pGroupColVals) == NULL) {
H
Haojun Liao 已提交
91 92 93 94 95
    return TSDB_CODE_OUT_OF_MEMORY;
  }

  int32_t numOfGroupCols = taosArrayGetSize(pGroupColList);
  for (int32_t i = 0; i < numOfGroupCols; ++i) {
5
54liuyao 已提交
96
    SColumn* pCol = (SColumn*)taosArrayGet(pGroupColList, i);
97
    (*keyLen) += pCol->bytes;  // actual data + null_flag
H
Haojun Liao 已提交
98

99
    SGroupKeys key = {0};
100 101
    key.bytes = pCol->bytes;
    key.type = pCol->type;
H
Haojun Liao 已提交
102
    key.isNull = false;
103
    key.pData = taosMemoryCalloc(1, pCol->bytes);
H
Haojun Liao 已提交
104 105 106 107
    if (key.pData == NULL) {
      return TSDB_CODE_OUT_OF_MEMORY;
    }

H
Haojun Liao 已提交
108
    taosArrayPush((*pGroupColVals), &key);
H
Haojun Liao 已提交
109 110 111
  }

  int32_t nullFlagSize = sizeof(int8_t) * numOfGroupCols;
112
  (*keyLen) += nullFlagSize;
H
Haojun Liao 已提交
113

114
  (*keyBuf) = taosMemoryCalloc(1, (*keyLen));
H
Haojun Liao 已提交
115
  if ((*keyBuf) == NULL) {
H
Haojun Liao 已提交
116 117 118 119 120 121
    return TSDB_CODE_OUT_OF_MEMORY;
  }

  return TSDB_CODE_SUCCESS;
}

122 123
static bool groupKeyCompare(SArray* pGroupCols, SArray* pGroupColVals, SSDataBlock* pBlock, int32_t rowIndex,
                            int32_t numOfGroupCols) {
H
Haojun Liao 已提交
124 125
  SColumnDataAgg* pColAgg = NULL;
  for (int32_t i = 0; i < numOfGroupCols; ++i) {
H
Haojun Liao 已提交
126
    SColumn*         pCol = taosArrayGet(pGroupCols, i);
H
Haojun Liao 已提交
127 128
    SColumnInfoData* pColInfoData = taosArrayGet(pBlock->pDataBlock, pCol->slotId);
    if (pBlock->pBlockAgg != NULL) {
129
      pColAgg = pBlock->pBlockAgg[pCol->slotId];  // TODO is agg data matched?
H
Haojun Liao 已提交
130 131 132 133
    }

    bool isNull = colDataIsNull(pColInfoData, pBlock->info.rows, rowIndex, pColAgg);

H
Haojun Liao 已提交
134
    SGroupKeys* pkey = taosArrayGet(pGroupColVals, i);
H
Haojun Liao 已提交
135 136 137 138 139 140 141 142 143 144
    if (pkey->isNull && isNull) {
      continue;
    }

    if (isNull || pkey->isNull) {
      return false;
    }

    char* val = colDataGetData(pColInfoData, rowIndex);

wmmhello's avatar
wmmhello 已提交
145 146 147
    if (pkey->type == TSDB_DATA_TYPE_JSON) {
      int32_t dataLen = getJsonValueLen(val);

148
      if (memcmp(pkey->pData, val, dataLen) == 0) {
wmmhello's avatar
wmmhello 已提交
149 150 151 152 153
        continue;
      } else {
        return false;
      }
    } else if (IS_VAR_DATA_TYPE(pkey->type)) {
H
Haojun Liao 已提交
154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169
      int32_t len = varDataLen(val);
      if (len == varDataLen(pkey->pData) && memcmp(varDataVal(pkey->pData), varDataVal(val), len) == 0) {
        continue;
      } else {
        return false;
      }
    } else {
      if (memcmp(pkey->pData, val, pkey->bytes) != 0) {
        return false;
      }
    }
  }

  return true;
}

wmmhello's avatar
wmmhello 已提交
170
static void recordNewGroupKeys(SArray* pGroupCols, SArray* pGroupColVals, SSDataBlock* pBlock, int32_t rowIndex) {
H
Haojun Liao 已提交
171 172
  SColumnDataAgg* pColAgg = NULL;

173 174
  size_t numOfGroupCols = taosArrayGetSize(pGroupCols);

H
Haojun Liao 已提交
175
  for (int32_t i = 0; i < numOfGroupCols; ++i) {
H
Haojun Liao 已提交
176
    SColumn*         pCol = taosArrayGet(pGroupCols, i);
H
Haojun Liao 已提交
177 178 179
    SColumnInfoData* pColInfoData = taosArrayGet(pBlock->pDataBlock, pCol->slotId);

    if (pBlock->pBlockAgg != NULL) {
180
      pColAgg = pBlock->pBlockAgg[pCol->slotId];  // TODO is agg data matched?
H
Haojun Liao 已提交
181 182
    }

H
Haojun Liao 已提交
183
    SGroupKeys* pkey = taosArrayGet(pGroupColVals, i);
H
Haojun Liao 已提交
184 185 186
    if (colDataIsNull(pColInfoData, pBlock->info.rows, rowIndex, pColAgg)) {
      pkey->isNull = true;
    } else {
187
      pkey->isNull = false;
H
Haojun Liao 已提交
188
      char* val = colDataGetData(pColInfoData, rowIndex);
wmmhello's avatar
wmmhello 已提交
189
      if (pkey->type == TSDB_DATA_TYPE_JSON) {
190
        if (tTagIsJson(val)) {
wmmhello's avatar
wmmhello 已提交
191 192 193
          terrno = TSDB_CODE_QRY_JSON_IN_GROUP_ERROR;
          return;
        }
wmmhello's avatar
wmmhello 已提交
194 195 196
        int32_t dataLen = getJsonValueLen(val);
        memcpy(pkey->pData, val, dataLen);
      } else if (IS_VAR_DATA_TYPE(pkey->type)) {
H
Haojun Liao 已提交
197
        memcpy(pkey->pData, val, varDataTLen(val));
198
        ASSERT(varDataTLen(val) <= pkey->bytes);
H
Haojun Liao 已提交
199 200 201 202 203 204 205
      } else {
        memcpy(pkey->pData, val, pkey->bytes);
      }
    }
  }
}

wmmhello's avatar
wmmhello 已提交
206
static int32_t buildGroupKeys(void* pKey, const SArray* pGroupColVals) {
207
  ASSERT(pKey != NULL);
H
Haojun Liao 已提交
208 209 210 211 212 213 214 215 216 217 218 219
  size_t numOfGroupCols = taosArrayGetSize(pGroupColVals);

  char* isNull = (char*)pKey;
  char* pStart = (char*)pKey + sizeof(int8_t) * numOfGroupCols;
  for (int32_t i = 0; i < numOfGroupCols; ++i) {
    SGroupKeys* pkey = taosArrayGet(pGroupColVals, i);
    if (pkey->isNull) {
      isNull[i] = 1;
      continue;
    }

    isNull[i] = 0;
wmmhello's avatar
wmmhello 已提交
220 221 222 223 224
    if (pkey->type == TSDB_DATA_TYPE_JSON) {
      int32_t dataLen = getJsonValueLen(pkey->pData);
      memcpy(pStart, (pkey->pData), dataLen);
      pStart += dataLen;
    } else if (IS_VAR_DATA_TYPE(pkey->type)) {
H
Haojun Liao 已提交
225 226
      varDataCopy(pStart, pkey->pData);
      pStart += varDataTLen(pkey->pData);
227
      ASSERT(varDataTLen(pkey->pData) <= pkey->bytes);
H
Haojun Liao 已提交
228 229 230 231 232 233
    } else {
      memcpy(pStart, pkey->pData, pkey->bytes);
      pStart += pkey->bytes;
    }
  }

234
  return (int32_t)(pStart - (char*)pKey);
H
Haojun Liao 已提交
235 236 237 238 239
}

// assign the group keys or user input constant values if required
static void doAssignGroupKeys(SqlFunctionCtx* pCtx, int32_t numOfOutput, int32_t totalRows, int32_t rowIndex) {
  for (int32_t i = 0; i < numOfOutput; ++i) {
240
    if (pCtx[i].functionId == -1) {  // select count(*),key from t group by key.
H
Haojun Liao 已提交
241 242 243
      SResultRowEntryInfo* pEntryInfo = GET_RES_INFO(&pCtx[i]);

      SColumnInfoData* pColInfoData = pCtx[i].input.pData[0];
244
      // todo OPT all/all not NULL
H
Haojun Liao 已提交
245 246 247 248
      if (!colDataIsNull(pColInfoData, totalRows, rowIndex, NULL)) {
        char* dest = GET_ROWCELL_INTERBUF(pEntryInfo);
        char* data = colDataGetData(pColInfoData, rowIndex);

wmmhello's avatar
wmmhello 已提交
249 250 251 252
        if (pColInfoData->info.type == TSDB_DATA_TYPE_JSON) {
          int32_t dataLen = getJsonValueLen(data);
          memcpy(dest, data, dataLen);
        } else if (IS_VAR_DATA_TYPE(pColInfoData->info.type)) {
253 254 255 256
          varDataCopy(dest, data);
        } else {
          memcpy(dest, data, pColInfoData->info.bytes);
        }
257
      } else {  // it is a NULL value
H
Haojun Liao 已提交
258
        pEntryInfo->isNullRes = 1;
H
Haojun Liao 已提交
259
      }
H
Haojun Liao 已提交
260 261

      pEntryInfo->numOfRes = 1;
H
Haojun Liao 已提交
262 263 264 265 266 267 268 269
    }
  }
}

static void doHashGroupbyAgg(SOperatorInfo* pOperator, SSDataBlock* pBlock) {
  SExecTaskInfo*        pTaskInfo = pOperator->pTaskInfo;
  SGroupbyOperatorInfo* pInfo = pOperator->info;

270
  SqlFunctionCtx* pCtx = pOperator->exprSupp.pCtx;
H
Haojun Liao 已提交
271 272 273 274 275 276
  int32_t         numOfGroupCols = taosArrayGetSize(pInfo->pGroupCols);
  //  if (type == TSDB_DATA_TYPE_FLOAT || type == TSDB_DATA_TYPE_DOUBLE) {
  // qError("QInfo:0x%"PRIx64" group by not supported on double/float columns, abort", GET_TASKID(pRuntimeEnv));
  //    return;
  //  }

H
Haojun Liao 已提交
277
  int32_t len = 0;
wmmhello's avatar
wmmhello 已提交
278
  terrno = TSDB_CODE_SUCCESS;
H
Haojun Liao 已提交
279

H
Haojun Liao 已提交
280 281 282 283
  int32_t num = 0;
  for (int32_t j = 0; j < pBlock->info.rows; ++j) {
    // Compare with the previous row of this column, and do not set the output buffer again if they are identical.
    if (!pInfo->isInit) {
284
      recordNewGroupKeys(pInfo->pGroupCols, pInfo->pGroupColVals, pBlock, j);
wmmhello's avatar
wmmhello 已提交
285
      if (terrno != TSDB_CODE_SUCCESS) {  // group by json error
286
        T_LONG_JMP(pTaskInfo->env, terrno);
wmmhello's avatar
wmmhello 已提交
287
      }
H
Haojun Liao 已提交
288 289 290 291 292
      pInfo->isInit = true;
      num++;
      continue;
    }

H
Haojun Liao 已提交
293
    bool equal = groupKeyCompare(pInfo->pGroupCols, pInfo->pGroupColVals, pBlock, j, numOfGroupCols);
H
Haojun Liao 已提交
294 295 296 297 298
    if (equal) {
      num++;
      continue;
    }

H
Haojun Liao 已提交
299
    // The first row of a new block does not belongs to the previous existed group
300
    if (j == 0) {
H
Haojun Liao 已提交
301
      num++;
302
      recordNewGroupKeys(pInfo->pGroupCols, pInfo->pGroupColVals, pBlock, j);
wmmhello's avatar
wmmhello 已提交
303
      if (terrno != TSDB_CODE_SUCCESS) {  // group by json error
304
        T_LONG_JMP(pTaskInfo->env, terrno);
wmmhello's avatar
wmmhello 已提交
305
      }
H
Haojun Liao 已提交
306 307 308
      continue;
    }

H
Haojun Liao 已提交
309
    len = buildGroupKeys(pInfo->keyBuf, pInfo->pGroupColVals);
310
    int32_t ret = setGroupResultOutputBuf(pOperator, &(pInfo->binfo), pOperator->exprSupp.numOfExprs, pInfo->keyBuf,
H
Haojun Liao 已提交
311
                                          len, pBlock->info.id.groupId, pInfo->aggSup.pResultBuf, &pInfo->aggSup);
H
Haojun Liao 已提交
312
    if (ret != TSDB_CODE_SUCCESS) {  // null data, too many state code
S
Shengliang Guan 已提交
313
      T_LONG_JMP(pTaskInfo->env, TSDB_CODE_APP_ERROR);
H
Haojun Liao 已提交
314 315 316
    }

    int32_t rowIndex = j - num;
dengyihao's avatar
dengyihao 已提交
317 318
    applyAggFunctionOnPartialTuples(pTaskInfo, pCtx, NULL, rowIndex, num, pBlock->info.rows,
                                    pOperator->exprSupp.numOfExprs);
H
Haojun Liao 已提交
319 320

    // assign the group keys or user input constant values if required
321
    doAssignGroupKeys(pCtx, pOperator->exprSupp.numOfExprs, pBlock->info.rows, rowIndex);
322
    recordNewGroupKeys(pInfo->pGroupCols, pInfo->pGroupColVals, pBlock, j);
H
Haojun Liao 已提交
323 324 325 326
    num = 1;
  }

  if (num > 0) {
H
Haojun Liao 已提交
327
    len = buildGroupKeys(pInfo->keyBuf, pInfo->pGroupColVals);
328
    int32_t ret = setGroupResultOutputBuf(pOperator, &(pInfo->binfo), pOperator->exprSupp.numOfExprs, pInfo->keyBuf,
H
Haojun Liao 已提交
329
                                          len, pBlock->info.id.groupId, pInfo->aggSup.pResultBuf, &pInfo->aggSup);
H
Haojun Liao 已提交
330
    if (ret != TSDB_CODE_SUCCESS) {
S
Shengliang Guan 已提交
331
      T_LONG_JMP(pTaskInfo->env, TSDB_CODE_APP_ERROR);
H
Haojun Liao 已提交
332 333 334
    }

    int32_t rowIndex = pBlock->info.rows - num;
dengyihao's avatar
dengyihao 已提交
335 336
    applyAggFunctionOnPartialTuples(pTaskInfo, pCtx, NULL, rowIndex, num, pBlock->info.rows,
                                    pOperator->exprSupp.numOfExprs);
337
    doAssignGroupKeys(pCtx, pOperator->exprSupp.numOfExprs, pBlock->info.rows, rowIndex);
H
Haojun Liao 已提交
338 339 340
  }
}

341 342 343 344
static SSDataBlock* buildGroupResultDataBlock(SOperatorInfo* pOperator) {
  SGroupbyOperatorInfo* pInfo = pOperator->info;

  SSDataBlock* pRes = pInfo->binfo.pRes;
345
  while (1) {
346
    doBuildResultDatablock(pOperator, &pInfo->binfo, &pInfo->groupResInfo, pInfo->aggSup.pResultBuf);
H
Haojun Liao 已提交
347
    doFilter(pRes, pOperator->exprSupp.pFilterInfo, NULL);
348

349
    if (!hasRemainResults(&pInfo->groupResInfo)) {
H
Haojun Liao 已提交
350
      setOperatorCompleted(pOperator);
351 352 353 354 355 356 357 358 359
      break;
    }

    if (pRes->info.rows > 0) {
      break;
    }
  }

  pOperator->resultInfo.totalRows += pRes->info.rows;
360
  return (pRes->info.rows == 0) ? NULL : pRes;
361 362
}

363
static SSDataBlock* hashGroupbyAggregate(SOperatorInfo* pOperator) {
H
Haojun Liao 已提交
364 365 366 367
  if (pOperator->status == OP_EXEC_DONE) {
    return NULL;
  }

368 369
  SExecTaskInfo* pTaskInfo = pOperator->pTaskInfo;

H
Haojun Liao 已提交
370 371
  SGroupbyOperatorInfo* pInfo = pOperator->info;
  if (pOperator->status == OP_RES_TO_RETURN) {
372
    return buildGroupResultDataBlock(pOperator);
H
Haojun Liao 已提交
373 374
  }

375 376 377
  int32_t order = TSDB_ORDER_ASC;
  int32_t scanFlag = MAIN_SCAN;

378
  int64_t        st = taosGetTimestampUs();
H
Haojun Liao 已提交
379 380 381
  SOperatorInfo* downstream = pOperator->pDownstream[0];

  while (1) {
382
    SSDataBlock* pBlock = downstream->fpSet.getNextFn(downstream);
H
Haojun Liao 已提交
383 384 385 386
    if (pBlock == NULL) {
      break;
    }

387 388
    int32_t code = getTableScanInfo(pOperator, &order, &scanFlag);
    if (code != TSDB_CODE_SUCCESS) {
389
      T_LONG_JMP(pTaskInfo->env, code);
390 391
    }

H
Haojun Liao 已提交
392
    // the pDataBlock are always the same one, no need to call this again
393
    setInputDataBlock(&pOperator->exprSupp, pBlock, order, scanFlag, true);
394

395
    // there is an scalar expression that needs to be calculated right before apply the group aggregation.
396
    if (pInfo->scalarSup.pExprInfo != NULL) {
397 398
      pTaskInfo->code = projectApplyFunctions(pInfo->scalarSup.pExprInfo, pBlock, pBlock, pInfo->scalarSup.pCtx,
                                              pInfo->scalarSup.numOfExprs, NULL);
399
      if (pTaskInfo->code != TSDB_CODE_SUCCESS) {
400
        T_LONG_JMP(pTaskInfo->env, pTaskInfo->code);
401
      }
402 403
    }

H
Haojun Liao 已提交
404 405 406 407
    doHashGroupbyAgg(pOperator, pBlock);
  }

  pOperator->status = OP_RES_TO_RETURN;
H
Haojun Liao 已提交
408

409 410 411 412 413 414 415 416 417 418 419 420 421 422
#if 0
  if(pOperator->fpSet.encodeResultRow){
    char *result = NULL;
    int32_t length = 0;
    pOperator->fpSet.encodeResultRow(pOperator, &result, &length);
    SAggSupporter* pSup = &pInfo->aggSup;
    taosHashClear(pSup->pResultRowHashTable);
    pInfo->binfo.resultRowInfo.size = 0;
    pOperator->fpSet.decodeResultRow(pOperator, result);
    if(result){
      taosMemoryFree(result);
    }
  }
#endif
423
  initGroupedResultInfo(&pInfo->groupResInfo, pInfo->aggSup.pResultRowHashTable, 0);
424

425
  pOperator->cost.openCost = (taosGetTimestampUs() - st) / 1000.0;
426
  return buildGroupResultDataBlock(pOperator);
H
Haojun Liao 已提交
427 428
}

5
54liuyao 已提交
429
SOperatorInfo* createGroupOperatorInfo(SOperatorInfo* downstream, SAggPhysiNode* pAggNode, SExecTaskInfo* pTaskInfo) {
H
Haojun Liao 已提交
430 431 432 433 434 435
  SGroupbyOperatorInfo* pInfo = taosMemoryCalloc(1, sizeof(SGroupbyOperatorInfo));
  SOperatorInfo*        pOperator = taosMemoryCalloc(1, sizeof(SOperatorInfo));
  if (pInfo == NULL || pOperator == NULL) {
    goto _error;
  }

H
Haojun Liao 已提交
436
  SSDataBlock* pResBlock = createDataBlockFromDescNode(pAggNode->node.pOutputDataBlockDesc);
H
Haojun Liao 已提交
437 438 439 440 441 442 443 444 445
  initBasicInfo(&pInfo->binfo, pResBlock);

  int32_t    numOfScalarExpr = 0;
  SExprInfo* pScalarExprInfo = NULL;
  if (pAggNode->pExprs != NULL) {
    pScalarExprInfo = createExprInfo(pAggNode->pExprs, NULL, &numOfScalarExpr);
  }

  pInfo->pGroupCols = extractColumnInfo(pAggNode->pGroupKeys);
446 447 448 449
  int32_t code = initExprSupp(&pInfo->scalarSup, pScalarExprInfo, numOfScalarExpr);
  if (code != TSDB_CODE_SUCCESS) {
    goto _error;
  }
450

H
Haojun Liao 已提交
451
  initResultSizeInfo(&pOperator->resultInfo, 4096);
H
Haojun Liao 已提交
452 453
  blockDataEnsureCapacity(pInfo->binfo.pRes, pOperator->resultInfo.capacity);

H
Haojun Liao 已提交
454
  code = initGroupOptrInfo(&pInfo->pGroupColVals, &pInfo->groupKeyLen, &pInfo->keyBuf, pInfo->pGroupCols);
H
Haojun Liao 已提交
455 456 457 458
  if (code != TSDB_CODE_SUCCESS) {
    goto _error;
  }

H
Haojun Liao 已提交
459 460
  int32_t    num = 0;
  SExprInfo* pExprInfo = createExprInfo(pAggNode->pAggFuncs, pAggNode->pGroupKeys, &num);
H
Haojun Liao 已提交
461
  code = initAggSup(&pOperator->exprSupp, &pInfo->aggSup, pExprInfo, num, pInfo->groupKeyLen, pTaskInfo->id.str);
462 463 464 465
  if (code != TSDB_CODE_SUCCESS) {
    goto _error;
  }

466 467 468 469 470
  code = filterInitFromNode((SNode*)pAggNode->node.pConditions, &pOperator->exprSupp.pFilterInfo, 0);
  if (code != TSDB_CODE_SUCCESS) {
    goto _error;
  }

471
  initResultRowInfo(&pInfo->binfo.resultRowInfo);
472
  setOperatorInfo(pOperator, "GroupbyAggOperator", 0, true, OP_NOT_OPENED, pInfo, pTaskInfo);
H
Haojun Liao 已提交
473

dengyihao's avatar
dengyihao 已提交
474 475
  pOperator->fpSet = createOperatorFpSet(optrDummyOpenFn, hashGroupbyAggregate, NULL, destroyGroupOperatorInfo,
                                         optrDefaultBufFn, NULL);
H
Haojun Liao 已提交
476
  code = appendDownstream(pOperator, &downstream, 1);
477 478 479 480
  if (code != TSDB_CODE_SUCCESS) {
    goto _error;
  }

H
Haojun Liao 已提交
481 482
  return pOperator;

483
_error:
H
Haojun Liao 已提交
484
  pTaskInfo->code = TSDB_CODE_OUT_OF_MEMORY;
H
Haojun Liao 已提交
485 486 487
  if (pInfo != NULL) {
    destroyGroupOperatorInfo(pInfo);
  }
H
Haojun Liao 已提交
488 489
  taosMemoryFreeClear(pOperator);
  return NULL;
490 491
}

H
Haojun Liao 已提交
492 493 494 495
static void doHashPartition(SOperatorInfo* pOperator, SSDataBlock* pBlock) {
  SPartitionOperatorInfo* pInfo = pOperator->info;

  for (int32_t j = 0; j < pBlock->info.rows; ++j) {
496
    recordNewGroupKeys(pInfo->pGroupCols, pInfo->pGroupColVals, pBlock, j);
H
Haojun Liao 已提交
497 498
    int32_t len = buildGroupKeys(pInfo->keyBuf, pInfo->pGroupColVals);

499
    SDataGroupInfo* pGroupInfo = NULL;
500
    void*           pPage = getCurrentDataGroupInfo(pInfo, &pGroupInfo, len);
H
Haojun Liao 已提交
501

502 503 504 505 506
    pGroupInfo->numOfRows += 1;

    // group id
    if (pGroupInfo->groupId == 0) {
      pGroupInfo->groupId = calcGroupId(pInfo->keyBuf, len);
H
Haojun Liao 已提交
507 508
    }

509
    // number of rows
510
    int32_t* rows = (int32_t*)pPage;
H
Haojun Liao 已提交
511

512
    size_t numOfCols = pOperator->exprSupp.numOfExprs;
513
    for (int32_t i = 0; i < numOfCols; ++i) {
514
      SExprInfo* pExpr = &pOperator->exprSupp.pExprInfo[i];
515
      int32_t    slotId = pExpr->base.pParam[0].pCol->slotId;
516 517

      SColumnInfoData* pColInfoData = taosArrayGet(pBlock->pDataBlock, slotId);
H
Haojun Liao 已提交
518

H
Haojun Liao 已提交
519 520
      int32_t bytes = pColInfoData->info.bytes;
      int32_t startOffset = pInfo->columnOffset[i];
H
Haojun Liao 已提交
521

522
      int32_t* columnLen = NULL;
523
      int32_t  contentLen = 0;
H
Haojun Liao 已提交
524 525

      if (IS_VAR_DATA_TYPE(pColInfoData->info.type)) {
wafwerar's avatar
wafwerar 已提交
526
        int32_t* offset = (int32_t*)((char*)pPage + startOffset);
527 528
        columnLen = (int32_t*)((char*)pPage + startOffset + sizeof(int32_t) * pInfo->rowCapacity);
        char* data = (char*)((char*)columnLen + sizeof(int32_t));
H
Haojun Liao 已提交
529 530 531 532

        if (colDataIsNull_s(pColInfoData, j)) {
          offset[(*rows)] = -1;
          contentLen = 0;
533
        } else if (pColInfoData->info.type == TSDB_DATA_TYPE_JSON) {
wmmhello's avatar
wmmhello 已提交
534
          offset[*rows] = (*columnLen);
535
          char*   src = colDataGetData(pColInfoData, j);
wmmhello's avatar
wmmhello 已提交
536 537 538 539
          int32_t dataLen = getJsonValueLen(src);

          memcpy(data + (*columnLen), src, dataLen);
          int32_t v = (data + (*columnLen) + dataLen - (char*)pPage);
540
          ASSERT(v > 0);
wmmhello's avatar
wmmhello 已提交
541 542

          contentLen = dataLen;
H
Haojun Liao 已提交
543 544 545 546
        } else {
          offset[*rows] = (*columnLen);
          char* src = colDataGetData(pColInfoData, j);
          memcpy(data + (*columnLen), src, varDataTLen(src));
547
          int32_t v = (data + (*columnLen) + varDataTLen(src) - (char*)pPage);
548
          ASSERT(v > 0);
549

H
Haojun Liao 已提交
550 551
          contentLen = varDataTLen(src);
        }
H
Haojun Liao 已提交
552
      } else {
wafwerar's avatar
wafwerar 已提交
553
        char* bitmap = (char*)pPage + startOffset;
554 555
        columnLen = (int32_t*)((char*)pPage + startOffset + BitmapLen(pInfo->rowCapacity));
        char* data = (char*)columnLen + sizeof(int32_t);
H
Haojun Liao 已提交
556 557 558

        bool isNull = colDataIsNull_f(pColInfoData->nullbitmap, j);
        if (isNull) {
H
Haojun Liao 已提交
559
          colDataSetNull_f(bitmap, (*rows));
H
Haojun Liao 已提交
560
        } else {
H
Haojun Liao 已提交
561
          memcpy(data + (*columnLen), colDataGetData(pColInfoData, j), bytes);
562
          ASSERT((data + (*columnLen) + bytes - (char*)pPage) <= getBufPageSize(pInfo->pBuf));
H
Haojun Liao 已提交
563
        }
H
Haojun Liao 已提交
564
        contentLen = bytes;
H
Haojun Liao 已提交
565
      }
H
Haojun Liao 已提交
566 567

      (*columnLen) += contentLen;
568
      ASSERT(*columnLen >= 0);
H
Haojun Liao 已提交
569 570
    }

H
Haojun Liao 已提交
571 572
    (*rows) += 1;

H
Haojun Liao 已提交
573 574 575
    setBufPageDirty(pPage, true);
    releaseBufPage(pInfo->pBuf, pPage);
  }
H
Haojun Liao 已提交
576 577 578 579 580 581
}

void* getCurrentDataGroupInfo(const SPartitionOperatorInfo* pInfo, SDataGroupInfo** pGroupInfo, int32_t len) {
  SDataGroupInfo* p = taosHashGet(pInfo->pGroupSet, pInfo->keyBuf, len);

  void* pPage = NULL;
582
  if (p == NULL) {  // it is a new group
H
Haojun Liao 已提交
583 584 585 586 587 588 589
    SDataGroupInfo gi = {0};
    gi.pPageList = taosArrayInit(100, sizeof(int32_t));
    taosHashPut(pInfo->pGroupSet, pInfo->keyBuf, len, &gi, sizeof(SDataGroupInfo));

    p = taosHashGet(pInfo->pGroupSet, pInfo->keyBuf, len);

    int32_t pageId = 0;
590
    pPage = getNewBufPage(pInfo->pBuf, &pageId);
H
Haojun Liao 已提交
591 592
    taosArrayPush(p->pPageList, &pageId);

593
    *(int32_t*)pPage = 0;
H
Haojun Liao 已提交
594 595 596 597
  } else {
    int32_t* curId = taosArrayGetLast(p->pPageList);
    pPage = getBufPage(pInfo->pBuf, *curId);

598
    int32_t* rows = (int32_t*)pPage;
H
Haojun Liao 已提交
599
    if (*rows >= pInfo->rowCapacity) {
600 601 602
      // release buffer
      releaseBufPage(pInfo->pBuf, pPage);

H
Haojun Liao 已提交
603 604
      // add a new page for current group
      int32_t pageId = 0;
605
      pPage = getNewBufPage(pInfo->pBuf, &pageId);
H
Haojun Liao 已提交
606
      taosArrayPush(p->pPageList, &pageId);
607
      memset(pPage, 0, getBufPageSize(pInfo->pBuf));
H
Haojun Liao 已提交
608 609
    }
  }
H
Haojun Liao 已提交
610

H
Haojun Liao 已提交
611 612 613 614 615 616 617 618 619 620 621 622 623 624
  *pGroupInfo = p;
  return pPage;
}

uint64_t calcGroupId(char* pData, int32_t len) {
  T_MD5_CTX context;
  tMD5Init(&context);
  tMD5Update(&context, (uint8_t*)pData, len);
  tMD5Final(&context);

  // NOTE: only extract the initial 8 bytes of the final MD5 digest
  uint64_t id = 0;
  memcpy(&id, context.digest, sizeof(uint64_t));
  return id;
H
Haojun Liao 已提交
625 626
}

H
Haojun Liao 已提交
627
int32_t* setupColumnOffset(const SSDataBlock* pBlock, int32_t rowCapacity) {
628
  size_t   numOfCols = taosArrayGetSize(pBlock->pDataBlock);
629
  int32_t* offset = taosMemoryCalloc(numOfCols, sizeof(int32_t));
H
Haojun Liao 已提交
630

631 632
  offset[0] = sizeof(int32_t) +
              sizeof(uint64_t);  // the number of rows in current page, ref to SSDataBlock paged serialization format
H
Haojun Liao 已提交
633

634
  for (int32_t i = 0; i < numOfCols - 1; ++i) {
H
Haojun Liao 已提交
635 636 637 638
    SColumnInfoData* pColInfoData = taosArrayGet(pBlock->pDataBlock, i);

    int32_t bytes = pColInfoData->info.bytes;
    int32_t payloadLen = bytes * rowCapacity;
639

H
Haojun Liao 已提交
640 641 642 643 644 645 646 647 648 649 650 651
    if (IS_VAR_DATA_TYPE(pColInfoData->info.type)) {
      // offset segment + content length + payload
      offset[i + 1] = rowCapacity * sizeof(int32_t) + sizeof(int32_t) + payloadLen + offset[i];
    } else {
      // bitmap + content length + payload
      offset[i + 1] = BitmapLen(rowCapacity) + sizeof(int32_t) + payloadLen + offset[i];
    }
  }

  return offset;
}

5
54liuyao 已提交
652
static void clearPartitionOperator(SPartitionOperatorInfo* pInfo) {
653 654 655 656
  int32_t size = taosArrayGetSize(pInfo->sortedGroupArray);
  for (int32_t i = 0; i < size; i++) {
    SDataGroupInfo* pGp = taosArrayGet(pInfo->sortedGroupArray, i);
    taosArrayDestroy(pGp->pPageList);
5
54liuyao 已提交
657
  }
658
  taosArrayClear(pInfo->sortedGroupArray);
5
54liuyao 已提交
659 660 661
  clearDiskbasedBuf(pInfo->pBuf);
}

662 663 664
static int compareDataGroupInfo(const void* group1, const void* group2) {
  const SDataGroupInfo* pGroupInfo1 = group1;
  const SDataGroupInfo* pGroupInfo2 = group2;
665 666

  if (pGroupInfo1->groupId == pGroupInfo2->groupId) {
667
    ASSERT(0);
668 669 670
    return 0;
  }

671
  return (pGroupInfo1->groupId < pGroupInfo2->groupId) ? -1 : 1;
672 673
}

H
Haojun Liao 已提交
674 675 676
static SSDataBlock* buildPartitionResult(SOperatorInfo* pOperator) {
  SPartitionOperatorInfo* pInfo = pOperator->info;

677 678
  SDataGroupInfo* pGroupInfo =
      (pInfo->groupIndex != -1) ? taosArrayGet(pInfo->sortedGroupArray, pInfo->groupIndex) : NULL;
679
  if (pInfo->groupIndex == -1 || pInfo->pageIndex >= taosArrayGetSize(pGroupInfo->pPageList)) {
H
Haojun Liao 已提交
680
    // try next group data
681 682
    ++pInfo->groupIndex;
    if (pInfo->groupIndex >= taosArrayGetSize(pInfo->sortedGroupArray)) {
H
Haojun Liao 已提交
683
      setOperatorCompleted(pOperator);
5
54liuyao 已提交
684
      clearPartitionOperator(pInfo);
H
Haojun Liao 已提交
685 686 687
      return NULL;
    }

688
    pGroupInfo = taosArrayGet(pInfo->sortedGroupArray, pInfo->groupIndex);
H
Haojun Liao 已提交
689 690 691 692
    pInfo->pageIndex = 0;
  }

  int32_t* pageId = taosArrayGet(pGroupInfo->pPageList, pInfo->pageIndex);
693
  void*    page = getBufPage(pInfo->pBuf, *pageId);
H
Haojun Liao 已提交
694

695
  blockDataEnsureCapacity(pInfo->binfo.pRes, pInfo->rowCapacity);
H
Haojun Liao 已提交
696
  blockDataFromBuf1(pInfo->binfo.pRes, page, pInfo->rowCapacity);
H
Haojun Liao 已提交
697 698

  pInfo->pageIndex += 1;
699
  releaseBufPage(pInfo->pBuf, page);
H
Haojun Liao 已提交
700

701
  blockDataUpdateTsWindow(pInfo->binfo.pRes, 0);
H
Haojun Liao 已提交
702
  pInfo->binfo.pRes->info.id.groupId = pGroupInfo->groupId;
703 704

  pOperator->resultInfo.totalRows += pInfo->binfo.pRes->info.rows;
H
Haojun Liao 已提交
705 706 707
  return pInfo->binfo.pRes;
}

708
static SSDataBlock* hashPartition(SOperatorInfo* pOperator) {
H
Haojun Liao 已提交
709 710
  if (pOperator->status == OP_EXEC_DONE) {
    return NULL;
711 712
  }

713 714 715
  SExecTaskInfo* pTaskInfo = pOperator->pTaskInfo;

  SPartitionOperatorInfo* pInfo = pOperator->info;
716
  SSDataBlock*            pRes = pInfo->binfo.pRes;
717

H
Haojun Liao 已提交
718
  if (pOperator->status == OP_RES_TO_RETURN) {
H
Haojun Liao 已提交
719 720
    blockDataCleanup(pRes);
    return buildPartitionResult(pOperator);
H
Haojun Liao 已提交
721 722
  }

723
  int64_t        st = taosGetTimestampUs();
H
Haojun Liao 已提交
724
  SOperatorInfo* downstream = pOperator->pDownstream[0];
H
Haojun Liao 已提交
725

H
Haojun Liao 已提交
726
  while (1) {
727
    SSDataBlock* pBlock = downstream->fpSet.getNextFn(downstream);
H
Haojun Liao 已提交
728 729 730
    if (pBlock == NULL) {
      break;
    }
H
Haojun Liao 已提交
731

732
    // there is an scalar expression that needs to be calculated right before apply the group aggregation.
733
    if (pInfo->scalarSup.pExprInfo != NULL) {
734 735
      pTaskInfo->code = projectApplyFunctions(pInfo->scalarSup.pExprInfo, pBlock, pBlock, pInfo->scalarSup.pCtx,
                                              pInfo->scalarSup.numOfExprs, NULL);
736
      if (pTaskInfo->code != TSDB_CODE_SUCCESS) {
737
        T_LONG_JMP(pTaskInfo->env, pTaskInfo->code);
738 739 740
      }
    }

wmmhello's avatar
wmmhello 已提交
741
    terrno = TSDB_CODE_SUCCESS;
H
Haojun Liao 已提交
742
    doHashPartition(pOperator, pBlock);
wmmhello's avatar
wmmhello 已提交
743
    if (terrno != TSDB_CODE_SUCCESS) {  // group by json error
744
      T_LONG_JMP(pTaskInfo->env, terrno);
wmmhello's avatar
wmmhello 已提交
745
    }
H
Haojun Liao 已提交
746 747
  }

748
  SArray* groupArray = taosArrayInit(taosHashGetSize(pInfo->pGroupSet), sizeof(SDataGroupInfo));
749 750

  void* pGroupIter = taosHashIterate(pInfo->pGroupSet, NULL);
751 752 753 754 755 756 757 758 759 760 761
  while (pGroupIter != NULL) {
    SDataGroupInfo* pGroupInfo = pGroupIter;
    taosArrayPush(groupArray, pGroupInfo);
    pGroupIter = taosHashIterate(pInfo->pGroupSet, pGroupIter);
  }

  taosArraySort(groupArray, compareDataGroupInfo);
  pInfo->sortedGroupArray = groupArray;
  pInfo->groupIndex = -1;
  taosHashClear(pInfo->pGroupSet);

762 763
  pOperator->cost.openCost = (taosGetTimestampUs() - st) / 1000.0;

H
Haojun Liao 已提交
764
  pOperator->status = OP_RES_TO_RETURN;
H
Haojun Liao 已提交
765 766 767 768
  blockDataEnsureCapacity(pRes, 4096);
  return buildPartitionResult(pOperator);
}

769
static void destroyPartitionOperatorInfo(void* param) {
H
Haojun Liao 已提交
770
  SPartitionOperatorInfo* pInfo = (SPartitionOperatorInfo*)param;
771
  cleanupBasicInfo(&pInfo->binfo);
H
Haojun Liao 已提交
772
  taosArrayDestroy(pInfo->pGroupCols);
773

774
  for (int i = 0; i < taosArrayGetSize(pInfo->pGroupColVals); i++) {
wmmhello's avatar
wmmhello 已提交
775 776 777
    SGroupKeys key = *(SGroupKeys*)taosArrayGet(pInfo->pGroupColVals, i);
    taosMemoryFree(key.pData);
  }
778

H
Haojun Liao 已提交
779
  taosArrayDestroy(pInfo->pGroupColVals);
H
Haojun Liao 已提交
780
  taosMemoryFree(pInfo->keyBuf);
dengyihao's avatar
dengyihao 已提交
781 782 783 784 785 786

  int32_t size = taosArrayGetSize(pInfo->sortedGroupArray);
  for (int32_t i = 0; i < size; i++) {
    SDataGroupInfo* pGp = taosArrayGet(pInfo->sortedGroupArray, i);
    taosArrayDestroy(pGp->pPageList);
  }
787
  taosArrayDestroy(pInfo->sortedGroupArray);
D
dapan1121 已提交
788 789 790 791 792 793 794 795

  void* pGroupIter = taosHashIterate(pInfo->pGroupSet, NULL);
  while (pGroupIter != NULL) {
    SDataGroupInfo* pGroupInfo = pGroupIter;
    taosArrayDestroy(pGroupInfo->pPageList);
    pGroupIter = taosHashIterate(pInfo->pGroupSet, pGroupIter);
  }

wmmhello's avatar
wmmhello 已提交
796
  taosHashCleanup(pInfo->pGroupSet);
H
Haojun Liao 已提交
797
  taosMemoryFree(pInfo->columnOffset);
798

799
  cleanupExprSupp(&pInfo->scalarSup);
H
Haojun Liao 已提交
800
  destroyDiskbasedBuf(pInfo->pBuf);
D
dapan1121 已提交
801
  taosMemoryFreeClear(param);
H
Haojun Liao 已提交
802 803
}

804 805
SOperatorInfo* createPartitionOperatorInfo(SOperatorInfo* downstream, SPartitionPhysiNode* pPartNode,
                                           SExecTaskInfo* pTaskInfo) {
H
Haojun Liao 已提交
806
  SPartitionOperatorInfo* pInfo = taosMemoryCalloc(1, sizeof(SPartitionOperatorInfo));
807
  SOperatorInfo*          pOperator = taosMemoryCalloc(1, sizeof(SOperatorInfo));
H
Haojun Liao 已提交
808
  if (pInfo == NULL || pOperator == NULL) {
H
Haojun Liao 已提交
809 810
    goto _error;
  }
811

812
  int32_t    numOfCols = 0;
813 814 815 816
  SExprInfo* pExprInfo = createExprInfo(pPartNode->pTargets, NULL, &numOfCols);
  pInfo->pGroupCols = extractPartitionColInfo(pPartNode->pPartitionKeys);

  if (pPartNode->pExprs != NULL) {
817
    int32_t    num = 0;
818
    SExprInfo* pExprInfo1 = createExprInfo(pPartNode->pExprs, NULL, &num);
819
    int32_t    code = initExprSupp(&pInfo->scalarSup, pExprInfo1, num);
820 821 822
    if (code != TSDB_CODE_SUCCESS) {
      goto _error;
    }
823
  }
H
Haojun Liao 已提交
824 825 826 827 828 829 830

  _hash_fn_t hashFn = taosGetDefaultHashFunction(TSDB_DATA_TYPE_BINARY);
  pInfo->pGroupSet = taosHashInit(100, hashFn, false, HASH_NO_LOCK);
  if (pInfo->pGroupSet == NULL) {
    goto _error;
  }

831
  uint32_t defaultPgsz = 0;
832
  uint32_t defaultBufsz = 0;
H
Haojun Liao 已提交
833

H
Haojun Liao 已提交
834
  pInfo->binfo.pRes = createDataBlockFromDescNode(pPartNode->node.pOutputDataBlockDesc);
H
Haojun Liao 已提交
835
  getBufferPgSize(pInfo->binfo.pRes->info.rowSize, &defaultPgsz, &defaultBufsz);
836

wafwerar's avatar
wafwerar 已提交
837 838 839 840 841 842
  if (!osTempSpaceAvailable()) {
    terrno = TSDB_CODE_NO_AVAIL_DISK;
    pTaskInfo->code = terrno;
    qError("Create partition operator info failed since %s", terrstr(terrno));
    goto _error;
  }
H
Haojun Liao 已提交
843

wafwerar's avatar
wafwerar 已提交
844
  int32_t code = createDiskbasedBuf(&pInfo->pBuf, defaultPgsz, defaultBufsz, pTaskInfo->id.str, tsTempDir);
H
Haojun Liao 已提交
845 846 847 848
  if (code != TSDB_CODE_SUCCESS) {
    goto _error;
  }

H
Haojun Liao 已提交
849 850
  pInfo->rowCapacity = blockDataGetCapacityInRow(pInfo->binfo.pRes, getBufPageSize(pInfo->pBuf));
  pInfo->columnOffset = setupColumnOffset(pInfo->binfo.pRes, pInfo->rowCapacity);
851
  code = initGroupOptrInfo(&pInfo->pGroupColVals, &pInfo->groupKeyLen, &pInfo->keyBuf, pInfo->pGroupCols);
H
Haojun Liao 已提交
852 853 854
  if (code != TSDB_CODE_SUCCESS) {
    goto _error;
  }
H
Haojun Liao 已提交
855

L
Liu Jicong 已提交
856 857
  setOperatorInfo(pOperator, "PartitionOperator", QUERY_NODE_PHYSICAL_PLAN_PARTITION, false, OP_NOT_OPENED, pInfo,
                  pTaskInfo);
858 859
  pOperator->exprSupp.numOfExprs = numOfCols;
  pOperator->exprSupp.pExprInfo = pExprInfo;
860

dengyihao's avatar
dengyihao 已提交
861 862
  pOperator->fpSet =
      createOperatorFpSet(optrDummyOpenFn, hashPartition, NULL, destroyPartitionOperatorInfo, optrDefaultBufFn, NULL);
H
Haojun Liao 已提交
863

H
Haojun Liao 已提交
864
  code = appendDownstream(pOperator, &downstream, 1);
865 866
  return pOperator;

867
_error:
H
Haojun Liao 已提交
868
  pTaskInfo->code = TSDB_CODE_OUT_OF_MEMORY;
H
Haojun Liao 已提交
869 870 871
  if (pInfo != NULL) {
    destroyPartitionOperatorInfo(pInfo);
  }
H
Haojun Liao 已提交
872
  taosMemoryFreeClear(pOperator);
873
  return NULL;
874 875
}

876 877 878
int32_t setGroupResultOutputBuf(SOperatorInfo* pOperator, SOptrBasicInfo* binfo, int32_t numOfCols, char* pData,
                                int16_t bytes, uint64_t groupId, SDiskbasedBuf* pBuf, SAggSupporter* pAggSup) {
  SExecTaskInfo*  pTaskInfo = pOperator->pTaskInfo;
879
  SResultRowInfo* pResultRowInfo = &binfo->resultRowInfo;
880
  SqlFunctionCtx* pCtx = pOperator->exprSupp.pCtx;
881 882 883 884 885

  SResultRow* pResultRow =
      doSetResultOutBufByKey(pBuf, pResultRowInfo, (char*)pData, bytes, true, groupId, pTaskInfo, false, pAggSup);
  assert(pResultRow != NULL);

886
  setResultRowInitCtx(pResultRow, pCtx, numOfCols, pOperator->exprSupp.rowEntryInfoOffset);
887
  return TSDB_CODE_SUCCESS;
D
dapan1121 已提交
888
}
889 890 891

uint64_t calGroupIdByData(SPartitionBySupporter* pParSup, SExprSupp* pExprSup, SSDataBlock* pBlock, int32_t rowId) {
  if (pExprSup->pExprInfo != NULL) {
892 893
    int32_t code =
        projectApplyFunctions(pExprSup->pExprInfo, pBlock, pBlock, pExprSup->pCtx, pExprSup->numOfExprs, NULL);
894 895 896 897 898
    if (code != TSDB_CODE_SUCCESS) {
      qError("calaculate group id error, code:%d", code);
    }
  }
  recordNewGroupKeys(pParSup->pGroupCols, pParSup->pGroupColVals, pBlock, rowId);
899
  int32_t  len = buildGroupKeys(pParSup->keyBuf, pParSup->pGroupColVals);
900 901 902 903
  uint64_t groupId = calcGroupId(pParSup->keyBuf, len);
  return groupId;
}

904
static bool hasRemainPartion(SStreamPartitionOperatorInfo* pInfo) { return pInfo->parIte != NULL; }
905 906 907

static SSDataBlock* buildStreamPartitionResult(SOperatorInfo* pOperator) {
  SStreamPartitionOperatorInfo* pInfo = pOperator->info;
908
  SSDataBlock*                  pDest = pInfo->binfo.pRes;
909
  ASSERT(hasRemainPartion(pInfo));
910 911
  SPartitionDataInfo* pParInfo = (SPartitionDataInfo*)pInfo->parIte;
  blockDataCleanup(pDest);
912
  int32_t      rows = taosArrayGetSize(pParInfo->rowIds);
913 914 915 916
  SSDataBlock* pSrc = pInfo->pInputDataBlock;
  for (int32_t i = 0; i < rows; i++) {
    int32_t rowIndex = *(int32_t*)taosArrayGet(pParInfo->rowIds, i);
    for (int32_t j = 0; j < pOperator->exprSupp.numOfExprs; j++) {
917
      int32_t          slotId = pOperator->exprSupp.pExprInfo[j].base.pParam[0].pCol->slotId;
918 919
      SColumnInfoData* pSrcCol = taosArrayGet(pSrc->pDataBlock, slotId);
      SColumnInfoData* pDestCol = taosArrayGet(pDest->pDataBlock, j);
920 921
      bool             isNull = colDataIsNull(pSrcCol, pSrc->info.rows, rowIndex, NULL);
      char*            pSrcData = colDataGetData(pSrcCol, rowIndex);
922 923 924
      colDataAppend(pDestCol, pDest->info.rows, pSrcData, isNull);
    }
    pDest->info.rows++;
L
Liu Jicong 已提交
925
    if (pInfo->tbnameCalSup.numOfExprs > 0 && i == 0) {
L
Liu Jicong 已提交
926 927 928 929
      void* tbname = NULL;
      if (streamStateGetParName(pOperator->pTaskInfo->streamInfo.pState, pParInfo->groupId, &tbname) == 0) {
        memcpy(pDest->info.parTbName, tbname, TSDB_TABLE_NAME_LEN);
        tdbFree(tbname);
930
      } else {
L
Liu Jicong 已提交
931 932 933 934 935 936 937
        SSDataBlock* pTmpBlock = blockCopyOneRow(pSrc, rowIndex);
        SSDataBlock* pResBlock = createDataBlock();
        pResBlock->info.rowSize = TSDB_TABLE_NAME_LEN;
        SColumnInfoData data = createColumnInfoData(TSDB_DATA_TYPE_VARCHAR, TSDB_TABLE_NAME_LEN, 0);
        taosArrayPush(pResBlock->pDataBlock, &data);
        blockDataEnsureCapacity(pResBlock, 1);
        projectApplyFunctions(pInfo->tbnameCalSup.pExprInfo, pResBlock, pTmpBlock, pInfo->tbnameCalSup.pCtx, 1, NULL);
938 939
        ASSERT(pResBlock->info.rows == 1);
        ASSERT(taosArrayGetSize(pResBlock->pDataBlock) == 1);
L
Liu Jicong 已提交
940
        SColumnInfoData* pCol = taosArrayGet(pResBlock->pDataBlock, 0);
941
        ASSERT(pCol->info.type == TSDB_DATA_TYPE_VARCHAR);
L
Liu Jicong 已提交
942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957
        void* pData = colDataGetVarData(pCol, 0);
        // TODO check tbname validity
        if (pData != (void*)-1) {
          memset(pDest->info.parTbName, 0, TSDB_TABLE_NAME_LEN);
          int32_t len = TMIN(varDataLen(pData), TSDB_TABLE_NAME_LEN - 1);
          memcpy(pDest->info.parTbName, varDataVal(pData), len);
          /*pDest->info.parTbName[len + 1] = 0;*/
        } else {
          pDest->info.parTbName[0] = 0;
        }
        if (pParInfo->groupId && pDest->info.parTbName[0]) {
          streamStatePutParName(pOperator->pTaskInfo->streamInfo.pState, pParInfo->groupId, pDest->info.parTbName);
        }
        /*printf("\n\n set name %s\n\n", pDest->info.parTbName);*/
        blockDataDestroy(pTmpBlock);
        blockDataDestroy(pResBlock);
L
Liu Jicong 已提交
958
      }
959
    }
960
  }
961 962
  taosArrayDestroy(pParInfo->rowIds);
  pParInfo->rowIds = NULL;
963
  blockDataUpdateTsWindow(pDest, pInfo->tsColIndex);
H
Haojun Liao 已提交
964
  pDest->info.id.groupId = pParInfo->groupId;
965 966
  pOperator->resultInfo.totalRows += pDest->info.rows;
  pInfo->parIte = taosHashIterate(pInfo->pPartitions, pInfo->parIte);
967
  ASSERT(pDest->info.rows > 0);
968 969 970 971 972 973 974 975
  printDataBlock(pDest, "stream partitionby");
  return pDest;
}

static void doStreamHashPartitionImpl(SStreamPartitionOperatorInfo* pInfo, SSDataBlock* pBlock) {
  pInfo->pInputDataBlock = pBlock;
  for (int32_t i = 0; i < pBlock->info.rows; ++i) {
    recordNewGroupKeys(pInfo->partitionSup.pGroupCols, pInfo->partitionSup.pGroupColVals, pBlock, i);
976 977 978
    int32_t             keyLen = buildGroupKeys(pInfo->partitionSup.keyBuf, pInfo->partitionSup.pGroupColVals);
    SPartitionDataInfo* pParData =
        (SPartitionDataInfo*)taosHashGet(pInfo->pPartitions, pInfo->partitionSup.keyBuf, keyLen);
979 980 981 982 983 984 985
    if (pParData) {
      taosArrayPush(pParData->rowIds, &i);
    } else {
      SPartitionDataInfo newParData = {0};
      newParData.groupId = calcGroupId(pInfo->partitionSup.keyBuf, keyLen);
      newParData.rowIds = taosArrayInit(64, sizeof(int32_t));
      taosArrayPush(newParData.rowIds, &i);
986
      taosHashPut(pInfo->pPartitions, pInfo->partitionSup.keyBuf, keyLen, &newParData, sizeof(SPartitionDataInfo));
987 988 989 990 991 992 993 994 995
    }
  }
}

static SSDataBlock* doStreamHashPartition(SOperatorInfo* pOperator) {
  if (pOperator->status == OP_EXEC_DONE) {
    return NULL;
  }

996
  SExecTaskInfo*                pTaskInfo = pOperator->pTaskInfo;
997 998 999 1000 1001
  SStreamPartitionOperatorInfo* pInfo = pOperator->info;
  if (hasRemainPartion(pInfo)) {
    return buildStreamPartitionResult(pOperator);
  }

1002
  int64_t        st = taosGetTimestampUs();
1003 1004 1005 1006 1007
  SOperatorInfo* downstream = pOperator->pDownstream[0];
  {
    pInfo->pInputDataBlock = NULL;
    SSDataBlock* pBlock = downstream->fpSet.getNextFn(downstream);
    if (pBlock == NULL) {
H
Haojun Liao 已提交
1008
      setOperatorCompleted(pOperator);
1009 1010 1011 1012 1013 1014 1015 1016 1017
      return NULL;
    }
    printDataBlock(pBlock, "stream partitionby recv");
    switch (pBlock->info.type) {
      case STREAM_NORMAL:
      case STREAM_PULL_DATA:
      case STREAM_INVALID:
        pInfo->binfo.pRes->info.type = pBlock->info.type;
        break;
1018 1019 1020
      case STREAM_DELETE_DATA: {
        copyDataBlock(pInfo->pDelRes, pBlock);
        pInfo->pDelRes->info.type = STREAM_DELETE_RESULT;
5
54liuyao 已提交
1021
        printDataBlock(pInfo->pDelRes, "stream partitionby delete");
1022
        return pInfo->pDelRes;
1023
      } break;
1024 1025 1026 1027 1028 1029
      default:
        return pBlock;
    }

    // there is an scalar expression that needs to be calculated right before apply the group aggregation.
    if (pInfo->scalarSup.pExprInfo != NULL) {
1030 1031
      pTaskInfo->code = projectApplyFunctions(pInfo->scalarSup.pExprInfo, pBlock, pBlock, pInfo->scalarSup.pCtx,
                                              pInfo->scalarSup.numOfExprs, NULL);
1032 1033 1034 1035 1036 1037 1038 1039
      if (pTaskInfo->code != TSDB_CODE_SUCCESS) {
        longjmp(pTaskInfo->env, pTaskInfo->code);
      }
    }
    taosHashClear(pInfo->pPartitions);
    doStreamHashPartitionImpl(pInfo, pBlock);
  }
  pOperator->cost.openCost = (taosGetTimestampUs() - st) / 1000.0;
1040

1041 1042 1043 1044 1045 1046 1047 1048 1049
  pInfo->parIte = taosHashIterate(pInfo->pPartitions, NULL);
  return buildStreamPartitionResult(pOperator);
}

static void destroyStreamPartitionOperatorInfo(void* param) {
  SStreamPartitionOperatorInfo* pInfo = (SStreamPartitionOperatorInfo*)param;
  cleanupBasicInfo(&pInfo->binfo);
  taosArrayDestroy(pInfo->partitionSup.pGroupCols);

1050
  for (int i = 0; i < taosArrayGetSize(pInfo->partitionSup.pGroupColVals); i++) {
1051 1052 1053 1054 1055 1056 1057
    SGroupKeys key = *(SGroupKeys*)taosArrayGet(pInfo->partitionSup.pGroupColVals, i);
    taosMemoryFree(key.pData);
  }
  taosArrayDestroy(pInfo->partitionSup.pGroupColVals);

  taosMemoryFree(pInfo->partitionSup.keyBuf);
  cleanupExprSupp(&pInfo->scalarSup);
L
Liu Jicong 已提交
1058 1059
  cleanupExprSupp(&pInfo->tbnameCalSup);
  cleanupExprSupp(&pInfo->tagCalSup);
1060
  blockDataDestroy(pInfo->pDelRes);
1061
  taosHashCleanup(pInfo->pPartitions);
1062 1063 1064 1065 1066 1067 1068 1069 1070 1071
  taosMemoryFreeClear(param);
}

void initParDownStream(SOperatorInfo* downstream, SPartitionBySupporter* pParSup, SExprSupp* pExpr) {
  if (downstream->operatorType != QUERY_NODE_PHYSICAL_PLAN_STREAM_SCAN) {
    return;
  }
  SStreamScanInfo* pScanInfo = downstream->info;
  pScanInfo->partitionSup = *pParSup;
  pScanInfo->pPartScalarSup = pExpr;
5
54liuyao 已提交
1072 1073 1074
  if (!pScanInfo->pUpdateInfo) {
    pScanInfo->pUpdateInfo = updateInfoInit(60000, TSDB_TIME_PRECISION_MILLI, 0);
  }
1075 1076
}

1077 1078
SOperatorInfo* createStreamPartitionOperatorInfo(SOperatorInfo* downstream, SStreamPartitionPhysiNode* pPartNode,
                                                 SExecTaskInfo* pTaskInfo) {
1079 1080 1081 1082 1083 1084
  SStreamPartitionOperatorInfo* pInfo = taosMemoryCalloc(1, sizeof(SStreamPartitionOperatorInfo));
  SOperatorInfo*                pOperator = taosMemoryCalloc(1, sizeof(SOperatorInfo));
  if (pInfo == NULL || pOperator == NULL) {
    goto _error;
  }
  int32_t code = TSDB_CODE_SUCCESS;
1085
  pInfo->partitionSup.pGroupCols = extractPartitionColInfo(pPartNode->part.pPartitionKeys);
1086

1087
  if (pPartNode->part.pExprs != NULL) {
1088
    int32_t    num = 0;
1089
    SExprInfo* pCalExprInfo = createExprInfo(pPartNode->part.pExprs, NULL, &num);
1090 1091 1092 1093 1094 1095
    code = initExprSupp(&pInfo->scalarSup, pCalExprInfo, num);
    if (code != TSDB_CODE_SUCCESS) {
      goto _error;
    }
  }

1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109
  if (pPartNode->pSubtable != NULL) {
    SExprInfo* pSubTableExpr = taosMemoryCalloc(1, sizeof(SExprInfo));
    if (pSubTableExpr == NULL) {
      code = TSDB_CODE_OUT_OF_MEMORY;
      goto _error;
    }
    pInfo->tbnameCalSup.pExprInfo = pSubTableExpr;
    createExprFromOneNode(pSubTableExpr, pPartNode->pSubtable, 0);
    code = initExprSupp(&pInfo->tbnameCalSup, pSubTableExpr, 1);
    if (code != TSDB_CODE_SUCCESS) {
      goto _error;
    }
  }

L
Liu Jicong 已提交
1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122
  if (pPartNode->pTags != NULL) {
    int32_t    numOfTags;
    SExprInfo* pTagExpr = createExprInfo(pPartNode->pTags, NULL, &numOfTags);
    if (pTagExpr == NULL) {
      terrno = TSDB_CODE_OUT_OF_MEMORY;
      goto _error;
    }
    if (initExprSupp(&pInfo->tagCalSup, pTagExpr, numOfTags) != 0) {
      terrno = TSDB_CODE_OUT_OF_MEMORY;
      goto _error;
    }
  }

1123
  int32_t keyLen = 0;
1124 1125
  code = initGroupOptrInfo(&pInfo->partitionSup.pGroupColVals, &keyLen, &pInfo->partitionSup.keyBuf,
                           pInfo->partitionSup.pGroupCols);
1126 1127 1128 1129 1130
  if (code != TSDB_CODE_SUCCESS) {
    goto _error;
  }
  pInfo->partitionSup.needCalc = true;

H
Haojun Liao 已提交
1131
  pInfo->binfo.pRes = createDataBlockFromDescNode(pPartNode->part.node.pOutputDataBlockDesc);
1132
  if (pInfo->binfo.pRes == NULL) {
1133 1134
    goto _error;
  }
1135 1136 1137

  blockDataEnsureCapacity(pInfo->binfo.pRes, 4096);

1138 1139
  pInfo->parIte = NULL;
  pInfo->pInputDataBlock = NULL;
1140

1141
  _hash_fn_t hashFn = taosGetDefaultHashFunction(TSDB_DATA_TYPE_BINARY);
1142 1143 1144
  pInfo->pPartitions = taosHashInit(1024, hashFn, false, HASH_NO_LOCK);
  pInfo->tsColIndex = 0;
  pInfo->pDelRes = createSpecialDataBlock(STREAM_DELETE_RESULT);
1145

1146
  int32_t    numOfCols = 0;
1147
  SExprInfo* pExprInfo = createExprInfo(pPartNode->part.pTargets, NULL, &numOfCols);
1148

L
Liu Jicong 已提交
1149 1150
  setOperatorInfo(pOperator, "StreamPartitionOperator", QUERY_NODE_PHYSICAL_PLAN_STREAM_PARTITION, false, OP_NOT_OPENED,
                  pInfo, pTaskInfo);
1151 1152
  pOperator->exprSupp.numOfExprs = numOfCols;
  pOperator->exprSupp.pExprInfo = pExprInfo;
dengyihao's avatar
dengyihao 已提交
1153 1154
  pOperator->fpSet = createOperatorFpSet(optrDummyOpenFn, doStreamHashPartition, NULL,
                                         destroyStreamPartitionOperatorInfo, optrDefaultBufFn, NULL);
1155 1156 1157 1158 1159

  initParDownStream(downstream, &pInfo->partitionSup, &pInfo->scalarSup);
  code = appendDownstream(pOperator, &downstream, 1);
  return pOperator;

1160
_error:
1161
  pTaskInfo->code = TSDB_CODE_OUT_OF_MEMORY;
1162
  destroyStreamPartitionOperatorInfo(pInfo);
1163 1164 1165
  taosMemoryFreeClear(pOperator);
  return NULL;
}
H
Haojun Liao 已提交
1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198

SArray* extractColumnInfo(SNodeList* pNodeList) {
  size_t  numOfCols = LIST_LENGTH(pNodeList);
  SArray* pList = taosArrayInit(numOfCols, sizeof(SColumn));
  if (pList == NULL) {
    terrno = TSDB_CODE_OUT_OF_MEMORY;
    return NULL;
  }

  for (int32_t i = 0; i < numOfCols; ++i) {
    STargetNode* pNode = (STargetNode*)nodesListGetNode(pNodeList, i);

    if (nodeType(pNode->pExpr) == QUERY_NODE_COLUMN) {
      SColumnNode* pColNode = (SColumnNode*)pNode->pExpr;

      SColumn c = extractColumnFromColumnNode(pColNode);
      taosArrayPush(pList, &c);
    } else if (nodeType(pNode->pExpr) == QUERY_NODE_VALUE) {
      SValueNode* pValNode = (SValueNode*)pNode->pExpr;
      SColumn     c = {0};
      c.slotId = pNode->slotId;
      c.colId = pNode->slotId;
      c.type = pValNode->node.type;
      c.bytes = pValNode->node.resType.bytes;
      c.scale = pValNode->node.resType.scale;
      c.precision = pValNode->node.resType.precision;

      taosArrayPush(pList, &c);
    }
  }

  return pList;
}