executil.c 64.6 KB
Newer Older
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 17
#include "function.h"
#include "functionMgt.h"
dengyihao's avatar
dengyihao 已提交
18 19
#include "index.h"
#include "os.h"
20
#include "tdatablock.h"
21
#include "thash.h"
22
#include "tmsg.h"
23
#include "ttime.h"
24

25 26
#include "executil.h"
#include "executorimpl.h"
H
Haojun Liao 已提交
27
#include "tcompression.h"
H
Haojun Liao 已提交
28

H
Haojun Liao 已提交
29 30 31 32
// If the numOfOutputGroups is 1, the data blocks that belongs to different groups will be provided randomly
// The numOfOutputGroups is specified by physical plan. and will not be affect by numOfGroups
struct STableListInfo {
  bool      oneTableForEachGroup;
dengyihao's avatar
dengyihao 已提交
33 34
  int32_t   numOfOuputGroups;  // the data block will be generated one by one
  int32_t*  groupOffset;       // keep the offset value for each group in the tableList
H
Haojun Liao 已提交
35
  SArray*   pTableList;
dengyihao's avatar
dengyihao 已提交
36
  SHashObj* map;  // speedup acquire the tableQueryInfo by table uid
H
Haojun Liao 已提交
37 38 39 40 41 42 43 44 45
  uint64_t  suid;
};

typedef struct tagFilterAssist {
  SHashObj* colHash;
  int32_t   index;
  SArray*   cInfoList;
} tagFilterAssist;

46
static int32_t removeInvalidUid(SArray* uids, SHashObj* tags);
47
static int32_t optimizeTbnameInCond(void* metaHandle, int64_t suid, SArray* pRes, SNode* pTagCond);
H
Haojun Liao 已提交
48
static int32_t optimizeTbnameInCondImpl(void* metaHandle, SArray* pExistedUidList, SNode* pTagCond);
49
static int32_t getTableList(void* metaHandle, void* pVnode, SScanPhysiNode* pScanNode, SNode* pTagCond,
50
                            SNode* pTagIndexCond, STableListInfo* pListInfo, const char* idstr);
H
Haojun Liao 已提交
51
static SSDataBlock* createTagValBlockForFilter(SArray* pColList, int32_t numOfTables, SArray* pUidTagList, void* metaHandle);
dengyihao's avatar
dengyihao 已提交
52

H
Haojun Liao 已提交
53 54
static int64_t getLimit(const SNode* pLimit) { return NULL == pLimit ? -1 : ((SLimitNode*)pLimit)->limit; }
static int64_t getOffset(const SNode* pLimit) { return NULL == pLimit ? -1 : ((SLimitNode*)pLimit)->offset; }
dengyihao's avatar
dengyihao 已提交
55

dengyihao's avatar
dengyihao 已提交
56 57
void initResultRowInfo(SResultRowInfo* pResultRowInfo) {
  pResultRowInfo->size = 0;
58
  pResultRowInfo->cur.pageId = -1;
59 60
}

dengyihao's avatar
dengyihao 已提交
61
void closeResultRow(SResultRow* pResultRow) { pResultRow->closed = true; }
62

63 64 65 66 67 68 69 70 71 72 73
void resetResultRow(SResultRow* pResultRow, size_t entrySize) {
  pResultRow->numOfRows = 0;
  pResultRow->closed = false;
  pResultRow->endInterp = false;
  pResultRow->startInterp = false;

  if (entrySize > 0) {
    memset(pResultRow->pEntryInfo, 0, entrySize);
  }
}

H
Haojun Liao 已提交
74
// TODO refactor: use macro
75
SResultRowEntryInfo* getResultEntryInfo(const SResultRow* pRow, int32_t index, const int32_t* offset) {
H
Haojun Liao 已提交
76
  assert(index >= 0 && offset != NULL);
dengyihao's avatar
dengyihao 已提交
77
  return (SResultRowEntryInfo*)((char*)pRow->pEntryInfo + offset[index]);
H
Haojun Liao 已提交
78 79
}

80 81 82
size_t getResultRowSize(SqlFunctionCtx* pCtx, int32_t numOfOutput) {
  int32_t rowSize = (numOfOutput * sizeof(SResultRowEntryInfo)) + sizeof(SResultRow);

dengyihao's avatar
dengyihao 已提交
83
  for (int32_t i = 0; i < numOfOutput; ++i) {
84 85 86
    rowSize += pCtx[i].resDataInfo.interBufSize;
  }

87 88
  rowSize += (numOfOutput * sizeof(bool));
  // expand rowSize to mark if col is null for top/bottom result(saveTupleData)
89
  return rowSize;
90 91
}

H
Haojun Liao 已提交
92 93 94 95
static void freeEx(void* p) {
  taosMemoryFree(*(void**)p);
}

H
Haojun Liao 已提交
96
void cleanupGroupResInfo(SGroupResInfo* pGroupResInfo) {
H
Haojun Liao 已提交
97
  taosMemoryFreeClear(pGroupResInfo->pBuf);
H
Haojun Liao 已提交
98
  if (pGroupResInfo->freeItem) {
99 100 101
//    taosArrayDestroy(pGroupResInfo->pRows);
    taosArrayDestroyEx(pGroupResInfo->pRows, freeEx);
    pGroupResInfo->freeItem = false;
H
Haojun Liao 已提交
102 103 104 105
    pGroupResInfo->pRows = NULL;
  } else {
    pGroupResInfo->pRows = taosArrayDestroy(pGroupResInfo->pRows);
  }
dengyihao's avatar
dengyihao 已提交
106
  pGroupResInfo->index = 0;
H
Haojun Liao 已提交
107 108
}

5
54liuyao 已提交
109
int32_t resultrowComparAsc(const void* p1, const void* p2) {
dengyihao's avatar
dengyihao 已提交
110 111
  SResKeyPos* pp1 = *(SResKeyPos**)p1;
  SResKeyPos* pp2 = *(SResKeyPos**)p2;
112 113

  if (pp1->groupId == pp2->groupId) {
dengyihao's avatar
dengyihao 已提交
114 115
    int64_t pts1 = *(int64_t*)pp1->key;
    int64_t pts2 = *(int64_t*)pp2->key;
116 117 118 119

    if (pts1 == pts2) {
      return 0;
    } else {
dengyihao's avatar
dengyihao 已提交
120
      return pts1 < pts2 ? -1 : 1;
121 122
    }
  } else {
dengyihao's avatar
dengyihao 已提交
123
    return pp1->groupId < pp2->groupId ? -1 : 1;
124 125 126
  }
}

dengyihao's avatar
dengyihao 已提交
127
static int32_t resultrowComparDesc(const void* p1, const void* p2) { return resultrowComparAsc(p2, p1); }
128

129
void initGroupedResultInfo(SGroupResInfo* pGroupResInfo, SSHashObj* pHashmap, int32_t order) {
H
Haojun Liao 已提交
130 131 132 133
  if (pGroupResInfo->pRows != NULL) {
    taosArrayDestroy(pGroupResInfo->pRows);
  }

134
  // extract the result rows information from the hash map
H
Haojun Liao 已提交
135 136
  int32_t size = tSimpleHashGetSize(pHashmap);

137
  void* pData = NULL;
H
Haojun Liao 已提交
138
  pGroupResInfo->pRows = taosArrayInit(size, POINTER_BYTES);
139

140
  size_t  keyLen = 0;
H
Haojun Liao 已提交
141 142
  int32_t iter = 0;
  int32_t bufLen = 0, offset = 0;
H
Haojun Liao 已提交
143

H
Haojun Liao 已提交
144
  // todo move away and record this during create window
145
  while ((pData = tSimpleHashIterate(pHashmap, pData, &iter)) != NULL) {
H
Haojun Liao 已提交
146 147 148
    /*void* key = */tSimpleHashGetKey(pData, &keyLen);
    bufLen += keyLen + sizeof(SResultRowPosition);
  }
149

H
Haojun Liao 已提交
150
  pGroupResInfo->pBuf = taosMemoryMalloc(bufLen);
H
Haojun Liao 已提交
151

H
Haojun Liao 已提交
152 153 154 155 156
  iter = 0;
  while ((pData = tSimpleHashIterate(pHashmap, pData, &iter)) != NULL) {
    void* key = tSimpleHashGetKey(pData, &keyLen);

    SResKeyPos* p = (SResKeyPos*) (pGroupResInfo->pBuf + offset);
157

dengyihao's avatar
dengyihao 已提交
158 159
    p->groupId = *(uint64_t*)key;
    p->pos = *(SResultRowPosition*)pData;
160
    memcpy(p->key, (char*)key + sizeof(uint64_t), keyLen - sizeof(uint64_t));
161
    taosArrayPush(pGroupResInfo->pRows, &p);
H
Haojun Liao 已提交
162 163

    offset += keyLen + sizeof(struct SResultRowPosition);
164 165
  }

166
  if (order == TSDB_ORDER_ASC || order == TSDB_ORDER_DESC) {
dengyihao's avatar
dengyihao 已提交
167
    __compar_fn_t fn = (order == TSDB_ORDER_ASC) ? resultrowComparAsc : resultrowComparDesc;
168
    size = POINTER_BYTES;
H
Haojun Liao 已提交
169
    taosSort(pGroupResInfo->pRows->pData, taosArrayGetSize(pGroupResInfo->pRows), size, fn);
170 171
  }

H
Haojun Liao 已提交
172
  pGroupResInfo->index = 0;
H
Haojun Liao 已提交
173 174 175
  assert(pGroupResInfo->index <= getNumOfTotalRes(pGroupResInfo));
}

H
Haojun Liao 已提交
176
void initMultiResInfoFromArrayList(SGroupResInfo* pGroupResInfo, SArray* pArrayList) {
H
Haojun Liao 已提交
177
  if (pGroupResInfo->pRows != NULL) {
H
Haojun Liao 已提交
178
    taosArrayDestroyP(pGroupResInfo->pRows, taosMemoryFree);
H
Haojun Liao 已提交
179 180
  }

H
Haojun Liao 已提交
181 182
  pGroupResInfo->freeItem = true;
  pGroupResInfo->pRows = pArrayList;
H
Haojun Liao 已提交
183
  pGroupResInfo->index = 0;
184
  ASSERT(pGroupResInfo->index <= getNumOfTotalRes(pGroupResInfo));
H
Haojun Liao 已提交
185 186
}

187
bool hasRemainResults(SGroupResInfo* pGroupResInfo) {
H
Haojun Liao 已提交
188 189 190 191 192 193 194 195 196 197 198 199
  if (pGroupResInfo->pRows == NULL) {
    return false;
  }

  return pGroupResInfo->index < taosArrayGetSize(pGroupResInfo->pRows);
}

int32_t getNumOfTotalRes(SGroupResInfo* pGroupResInfo) {
  if (pGroupResInfo->pRows == 0) {
    return 0;
  }

dengyihao's avatar
dengyihao 已提交
200
  return (int32_t)taosArrayGetSize(pGroupResInfo->pRows);
H
Haojun Liao 已提交
201 202
}

203
SArray* createSortInfo(SNodeList* pNodeList) {
204
  size_t numOfCols = 0;
205

206 207 208 209 210
  if (pNodeList != NULL) {
    numOfCols = LIST_LENGTH(pNodeList);
  } else {
    numOfCols = 0;
  }
211

212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231
  SArray* pList = taosArrayInit(numOfCols, sizeof(SBlockOrderInfo));
  if (pList == NULL) {
    terrno = TSDB_CODE_OUT_OF_MEMORY;
    return pList;
  }

  for (int32_t i = 0; i < numOfCols; ++i) {
    SOrderByExprNode* pSortKey = (SOrderByExprNode*)nodesListGetNode(pNodeList, i);
    SBlockOrderInfo   bi = {0};
    bi.order = (pSortKey->order == ORDER_ASC) ? TSDB_ORDER_ASC : TSDB_ORDER_DESC;
    bi.nullFirst = (pSortKey->nullOrder == NULL_ORDER_FIRST);

    SColumnNode* pColNode = (SColumnNode*)pSortKey->pExpr;
    bi.slotId = pColNode->slotId;
    taosArrayPush(pList, &bi);
  }

  return pList;
}

H
Haojun Liao 已提交
232
SSDataBlock* createDataBlockFromDescNode(SDataBlockDescNode* pNode) {
233
  int32_t numOfCols = LIST_LENGTH(pNode->pSlots);
H
Haojun Liao 已提交
234

235
  SSDataBlock* pBlock = createDataBlock();
H
Haojun Liao 已提交
236

H
Haojun Liao 已提交
237
  pBlock->info.id.blockId = pNode->dataBlockId;
238
  pBlock->info.type = STREAM_INVALID;
5
54liuyao 已提交
239
  pBlock->info.calWin = (STimeWindow){.skey = INT64_MIN, .ekey = INT64_MAX};
240
  pBlock->info.watermark = INT64_MIN;
H
Haojun Liao 已提交
241

242
  for (int32_t i = 0; i < numOfCols; ++i) {
M
Minglei Jin 已提交
243
    SSlotDescNode*  pDescNode = (SSlotDescNode*)nodesListGetNode(pNode->pSlots, i);
dengyihao's avatar
dengyihao 已提交
244 245
    SColumnInfoData idata =
        createColumnInfoData(pDescNode->dataType.type, pDescNode->dataType.bytes, pDescNode->slotId);
246 247 248
    idata.info.scale = pDescNode->dataType.scale;
    idata.info.precision = pDescNode->dataType.precision;

249
    blockDataAppendColInfo(pBlock, &idata);
H
Haojun Liao 已提交
250 251
  }

252 253 254
  return pBlock;
}

wmmhello's avatar
wmmhello 已提交
255 256
EDealRes doTranslateTagExpr(SNode** pNode, void* pContext) {
  SMetaReader* mr = (SMetaReader*)pContext;
dengyihao's avatar
dengyihao 已提交
257
  if (nodeType(*pNode) == QUERY_NODE_COLUMN) {
wmmhello's avatar
wmmhello 已提交
258 259
    SColumnNode* pSColumnNode = *(SColumnNode**)pNode;

dengyihao's avatar
dengyihao 已提交
260
    SValueNode* res = (SValueNode*)nodesMakeNode(QUERY_NODE_VALUE);
wmmhello's avatar
wmmhello 已提交
261 262 263 264 265 266 267 268 269
    if (NULL == res) {
      return DEAL_RES_ERROR;
    }

    res->translate = true;
    res->node.resType = pSColumnNode->node.resType;

    STagVal tagVal = {0};
    tagVal.cid = pSColumnNode->colId;
270
    const char* p = metaGetTableTagVal(mr->me.ctbEntry.pTags, pSColumnNode->node.resType.type, &tagVal);
wmmhello's avatar
wmmhello 已提交
271 272
    if (p == NULL) {
      res->node.resType.type = TSDB_DATA_TYPE_NULL;
dengyihao's avatar
dengyihao 已提交
273 274
    } else if (pSColumnNode->node.resType.type == TSDB_DATA_TYPE_JSON) {
      int32_t len = ((const STag*)p)->len;
wmmhello's avatar
wmmhello 已提交
275 276 277 278 279 280 281 282 283 284 285
      res->datum.p = taosMemoryCalloc(len + 1, 1);
      memcpy(res->datum.p, p, len);
    } else if (IS_VAR_DATA_TYPE(pSColumnNode->node.resType.type)) {
      res->datum.p = taosMemoryCalloc(tagVal.nData + VARSTR_HEADER_SIZE + 1, 1);
      memcpy(varDataVal(res->datum.p), tagVal.pData, tagVal.nData);
      varDataSetLen(res->datum.p, tagVal.nData);
    } else {
      nodesSetValueNodeValue(res, &(tagVal.i64));
    }
    nodesDestroyNode(*pNode);
    *pNode = (SNode*)res;
dengyihao's avatar
dengyihao 已提交
286 287 288 289
  } else if (nodeType(*pNode) == QUERY_NODE_FUNCTION) {
    SFunctionNode* pFuncNode = *(SFunctionNode**)pNode;
    if (pFuncNode->funcType == FUNCTION_TYPE_TBNAME) {
      SValueNode* res = (SValueNode*)nodesMakeNode(QUERY_NODE_VALUE);
wmmhello's avatar
wmmhello 已提交
290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308
      if (NULL == res) {
        return DEAL_RES_ERROR;
      }

      res->translate = true;
      res->node.resType = pFuncNode->node.resType;

      int32_t len = strlen(mr->me.name);
      res->datum.p = taosMemoryCalloc(len + VARSTR_HEADER_SIZE + 1, 1);
      memcpy(varDataVal(res->datum.p), mr->me.name, len);
      varDataSetLen(res->datum.p, len);
      nodesDestroyNode(*pNode);
      *pNode = (SNode*)res;
    }
  }

  return DEAL_RES_CONTINUE;
}

H
Haojun Liao 已提交
309
int32_t isQualifiedTable(STableKeyInfo* info, SNode* pTagCond, void* metaHandle, bool* pQualified) {
310
  int32_t     code = TSDB_CODE_SUCCESS;
dengyihao's avatar
dengyihao 已提交
311
  SMetaReader mr = {0};
312

wmmhello's avatar
wmmhello 已提交
313
  metaReaderInit(&mr, metaHandle, 0);
H
Haojun Liao 已提交
314
  code = metaGetTableEntryByUidCache(&mr, info->uid);
315 316
  if (TSDB_CODE_SUCCESS != code) {
    metaReaderClear(&mr);
M
Minglei Jin 已提交
317
    *pQualified = false;
318

M
Minglei Jin 已提交
319
    return TSDB_CODE_SUCCESS;
320
  }
wmmhello's avatar
wmmhello 已提交
321

dengyihao's avatar
dengyihao 已提交
322
  SNode* pTagCondTmp = nodesCloneNode(pTagCond);
wmmhello's avatar
wmmhello 已提交
323 324 325 326

  nodesRewriteExprPostOrder(&pTagCondTmp, doTranslateTagExpr, &mr);
  metaReaderClear(&mr);

327 328
  SNode* pNew = NULL;
  code = scalarCalculateConstants(pTagCondTmp, &pNew);
wmmhello's avatar
wmmhello 已提交
329
  if (TSDB_CODE_SUCCESS != code) {
wmmhello's avatar
wmmhello 已提交
330
    terrno = code;
wmmhello's avatar
wmmhello 已提交
331
    nodesDestroyNode(pTagCondTmp);
332 333 334
    *pQualified = false;

    return code;
wmmhello's avatar
wmmhello 已提交
335 336
  }

337
  ASSERT(nodeType(pNew) == QUERY_NODE_VALUE);
dengyihao's avatar
dengyihao 已提交
338
  SValueNode* pValue = (SValueNode*)pNew;
wmmhello's avatar
wmmhello 已提交
339

340
  ASSERT(pValue->node.resType.type == TSDB_DATA_TYPE_BOOL);
341 342
  *pQualified = pValue->datum.b;

wmmhello's avatar
wmmhello 已提交
343
  nodesDestroyNode(pNew);
344
  return TSDB_CODE_SUCCESS;
wmmhello's avatar
wmmhello 已提交
345 346
}

wmmhello's avatar
wmmhello 已提交
347 348 349 350
static EDealRes getColumn(SNode** pNode, void* pContext) {
  SColumnNode* pSColumnNode = NULL;
  if (QUERY_NODE_COLUMN == nodeType((*pNode))) {
    pSColumnNode = *(SColumnNode**)pNode;
H
Haojun Liao 已提交
351
  } else if (QUERY_NODE_FUNCTION == nodeType((*pNode))) {
wmmhello's avatar
wmmhello 已提交
352 353 354 355 356 357 358 359 360 361 362 363
    SFunctionNode* pFuncNode = *(SFunctionNode**)(pNode);
    if (pFuncNode->funcType == FUNCTION_TYPE_TBNAME) {
      pSColumnNode = (SColumnNode*)nodesMakeNode(QUERY_NODE_COLUMN);
      if (NULL == pSColumnNode) {
        return DEAL_RES_ERROR;
      }
      pSColumnNode->colId = -1;
      pSColumnNode->colType = COLUMN_TYPE_TBNAME;
      pSColumnNode->node.resType.type = TSDB_DATA_TYPE_VARCHAR;
      pSColumnNode->node.resType.bytes = TSDB_TABLE_FNAME_LEN - 1 + VARSTR_HEADER_SIZE;
      nodesDestroyNode(*pNode);
      *pNode = (SNode*)pSColumnNode;
H
Haojun Liao 已提交
364
    } else {
365
      return DEAL_RES_CONTINUE;
wmmhello's avatar
wmmhello 已提交
366
    }
H
Haojun Liao 已提交
367
  } else {
wmmhello's avatar
wmmhello 已提交
368
    return DEAL_RES_CONTINUE;
wmmhello's avatar
wmmhello 已提交
369
  }
wmmhello's avatar
wmmhello 已提交
370

H
Haojun Liao 已提交
371 372 373
  tagFilterAssist* pData = (tagFilterAssist*)pContext;
  void*            data = taosHashGet(pData->colHash, &pSColumnNode->colId, sizeof(pSColumnNode->colId));
  if (!data) {
wmmhello's avatar
wmmhello 已提交
374 375
    taosHashPut(pData->colHash, &pSColumnNode->colId, sizeof(pSColumnNode->colId), pNode, sizeof((*pNode)));
    pSColumnNode->slotId = pData->index++;
H
Haojun Liao 已提交
376 377 378
    SColumnInfo cInfo = {.colId = pSColumnNode->colId,
                         .type = pSColumnNode->node.resType.type,
                         .bytes = pSColumnNode->node.resType.bytes};
379 380 381
#if TAG_FILTER_DEBUG
    qDebug("tagfilter build column info, slotId:%d, colId:%d, type:%d", pSColumnNode->slotId, cInfo.colId, cInfo.type);
#endif
wmmhello's avatar
wmmhello 已提交
382
    taosArrayPush(pData->cInfoList, &cInfo);
H
Haojun Liao 已提交
383
  } else {
384 385
    SColumnNode* col = *(SColumnNode**)data;
    pSColumnNode->slotId = col->slotId;
wmmhello's avatar
wmmhello 已提交
386 387
  }

wmmhello's avatar
wmmhello 已提交
388 389 390 391 392 393 394 395 396 397
  return DEAL_RES_CONTINUE;
}

static int32_t createResultData(SDataType* pType, int32_t numOfRows, SScalarParam* pParam) {
  SColumnInfoData* pColumnData = taosMemoryCalloc(1, sizeof(SColumnInfoData));
  if (pColumnData == NULL) {
    terrno = TSDB_CODE_OUT_OF_MEMORY;
    return terrno;
  }

H
Haojun Liao 已提交
398 399 400
  pColumnData->info.type = pType->type;
  pColumnData->info.bytes = pType->bytes;
  pColumnData->info.scale = pType->scale;
wmmhello's avatar
wmmhello 已提交
401 402
  pColumnData->info.precision = pType->precision;

H
Haojun Liao 已提交
403
  int32_t code = colInfoDataEnsureCapacity(pColumnData, numOfRows, true);
wmmhello's avatar
wmmhello 已提交
404
  if (code != TSDB_CODE_SUCCESS) {
wmmhello's avatar
wmmhello 已提交
405
    terrno = code;
wmmhello's avatar
wmmhello 已提交
406 407 408 409 410 411 412 413 414
    taosMemoryFree(pColumnData);
    return terrno;
  }

  pParam->columnData = pColumnData;
  pParam->colAlloced = true;
  return TSDB_CODE_SUCCESS;
}

H
Haojun Liao 已提交
415 416 417 418 419 420 421 422
static void releaseColInfoData(void* pCol) {
  if (pCol) {
    SColumnInfoData* col = (SColumnInfoData*)pCol;
    colDataDestroy(col);
    taosMemoryFree(col);
  }
}

H
Haojun Liao 已提交
423 424 425 426 427 428 429
void freeItem(void* p) {
  STUidTagInfo *pInfo = p;
  if (pInfo->pTagVal != NULL) {
    taosMemoryFree(pInfo->pTagVal);
  }
}

H
Haojun Liao 已提交
430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447
int32_t getColInfoResultForGroupby(void* metaHandle, SNodeList* group, STableListInfo* pTableListInfo) {
  int32_t      code = TSDB_CODE_SUCCESS;
  SArray*      pBlockList = NULL;
  SSDataBlock* pResBlock = NULL;
  void*        keyBuf = NULL;
  SArray*      groupData = NULL;

  int32_t rows = taosArrayGetSize(pTableListInfo->pTableList);
  if (rows == 0) {
    return TDB_CODE_SUCCESS;
  }

  tagFilterAssist ctx = {0};
  ctx.colHash = taosHashInit(4, taosGetDefaultHashFunction(TSDB_DATA_TYPE_SMALLINT), false, HASH_NO_LOCK);
  if (ctx.colHash == NULL) {
    code = TSDB_CODE_OUT_OF_MEMORY;
    goto end;
  }
448

H
Haojun Liao 已提交
449 450 451 452 453 454 455 456 457 458 459 460 461
  ctx.index = 0;
  ctx.cInfoList = taosArrayInit(4, sizeof(SColumnInfo));
  if (ctx.cInfoList == NULL) {
    code = TSDB_CODE_OUT_OF_MEMORY;
    goto end;
  }

  SNode* pNode = NULL;
  FOREACH(pNode, group) {
    nodesRewriteExprPostOrder(&pNode, getColumn, (void*)&ctx);
    REPLACE_NODE(pNode);
  }

462
  SArray* pUidTagList = taosArrayInit(8, sizeof(STUidTagInfo));
H
Haojun Liao 已提交
463 464
  for (int32_t i = 0; i < rows; ++i) {
    STableKeyInfo* pkeyInfo = taosArrayGet(pTableListInfo->pTableList, i);
465 466
    STUidTagInfo info = {.uid = pkeyInfo->uid};
    taosArrayPush(pUidTagList, &info);
H
Haojun Liao 已提交
467 468 469
  }

  //  int64_t stt = taosGetTimestampUs();
470
  code = metaGetTableTags(metaHandle, pTableListInfo->suid, pUidTagList);
H
Haojun Liao 已提交
471 472 473 474
  if (code != TSDB_CODE_SUCCESS) {
    goto end;
  }

475
  int32_t numOfTables = taosArrayGetSize(pUidTagList);
H
Haojun Liao 已提交
476 477 478
  pResBlock = createTagValBlockForFilter(ctx.cInfoList, numOfTables, pUidTagList, metaHandle);
  if (pResBlock == NULL) {
    code = terrno;
H
Haojun Liao 已提交
479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504
    goto end;
  }

  //  int64_t st1 = taosGetTimestampUs();
  //  qDebug("generate tag block rows:%d, cost:%ld us", rows, st1-st);

  pBlockList = taosArrayInit(2, POINTER_BYTES);
  taosArrayPush(pBlockList, &pResBlock);

  groupData = taosArrayInit(2, POINTER_BYTES);
  FOREACH(pNode, group) {
    SScalarParam output = {0};

    switch (nodeType(pNode)) {
      case QUERY_NODE_VALUE:
        break;
      case QUERY_NODE_COLUMN:
      case QUERY_NODE_OPERATOR:
      case QUERY_NODE_FUNCTION: {
        SExprNode* expNode = (SExprNode*)pNode;
        code = createResultData(&expNode->resType, rows, &output);
        if (code != TSDB_CODE_SUCCESS) {
          goto end;
        }
        break;
      }
505

H
Haojun Liao 已提交
506 507 508 509
      default:
        code = TSDB_CODE_OPS_NOT_SUPPORT;
        goto end;
    }
510

H
Haojun Liao 已提交
511 512 513 514 515 516 517 518 519
    if (nodeType(pNode) == QUERY_NODE_COLUMN) {
      SColumnNode*     pSColumnNode = (SColumnNode*)pNode;
      SColumnInfoData* pColInfo = (SColumnInfoData*)taosArrayGet(pResBlock->pDataBlock, pSColumnNode->slotId);
      code = colDataAssign(output.columnData, pColInfo, rows, NULL);
    } else if (nodeType(pNode) == QUERY_NODE_VALUE) {
      continue;
    } else {
      code = scalarCalculate(pNode, pBlockList, &output);
    }
520

H
Haojun Liao 已提交
521 522 523 524
    if (code != TSDB_CODE_SUCCESS) {
      releaseColInfoData(output.columnData);
      goto end;
    }
525

H
Haojun Liao 已提交
526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543
    taosArrayPush(groupData, &output.columnData);
  }

  int32_t keyLen = 0;
  SNode*  node;
  FOREACH(node, group) {
    SExprNode* pExpr = (SExprNode*)node;
    keyLen += pExpr->resType.bytes;
  }

  int32_t nullFlagSize = sizeof(int8_t) * LIST_LENGTH(group);
  keyLen += nullFlagSize;

  keyBuf = taosMemoryCalloc(1, keyLen);
  if (keyBuf == NULL) {
    code = TSDB_CODE_OUT_OF_MEMORY;
    goto end;
  }
544

H
Haojun Liao 已提交
545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592
  for (int i = 0; i < rows; i++) {
    STableKeyInfo* info = taosArrayGet(pTableListInfo->pTableList, i);

    char* isNull = (char*)keyBuf;
    char* pStart = (char*)keyBuf + sizeof(int8_t) * LIST_LENGTH(group);
    for (int j = 0; j < taosArrayGetSize(groupData); j++) {
      SColumnInfoData* pValue = (SColumnInfoData*)taosArrayGetP(groupData, j);

      if (colDataIsNull_s(pValue, i)) {
        isNull[j] = 1;
      } else {
        isNull[j] = 0;
        char* data = colDataGetData(pValue, i);
        if (pValue->info.type == TSDB_DATA_TYPE_JSON) {
          if (tTagIsJson(data)) {
            code = TSDB_CODE_QRY_JSON_IN_GROUP_ERROR;
            goto end;
          }
          if (tTagIsJsonNull(data)) {
            isNull[j] = 1;
            continue;
          }
          int32_t len = getJsonValueLen(data);
          memcpy(pStart, data, len);
          pStart += len;
        } else if (IS_VAR_DATA_TYPE(pValue->info.type)) {
          memcpy(pStart, data, varDataTLen(data));
          pStart += varDataTLen(data);
        } else {
          memcpy(pStart, data, pValue->info.bytes);
          pStart += pValue->info.bytes;
        }
      }
    }

    int32_t len = (int32_t)(pStart - (char*)keyBuf);
    info->groupId = calcGroupId(keyBuf, len);
  }

  //  int64_t st2 = taosGetTimestampUs();
  //  qDebug("calculate tag block rows:%d, cost:%ld us", rows, st2-st1);

end:
  taosMemoryFreeClear(keyBuf);
  taosHashCleanup(ctx.colHash);
  taosArrayDestroy(ctx.cInfoList);
  blockDataDestroy(pResBlock);
  taosArrayDestroy(pBlockList);
H
Haojun Liao 已提交
593
  taosArrayDestroyEx(pUidTagList, freeItem);
H
Haojun Liao 已提交
594 595 596 597
  taosArrayDestroyP(groupData, releaseColInfoData);
  return code;
}

H
Haojun Liao 已提交
598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650
static int32_t nameComparFn(const void* p1, const void* p2) {
  const char* pName1 = *(const char**)p1;
  const char* pName2 = *(const char**)p2;

  int32_t ret = strcmp(pName1, pName2);
  if (ret == 0) {
    return 0;
  } else {
    return (ret > 0) ? 1 : -1;
  }
}

static SArray* getTableNameList(const SNodeListNode* pList) {
  int32_t    len = LIST_LENGTH(pList->pNodeList);
  SListCell* cell = pList->pNodeList->pHead;

  SArray* pTbList = taosArrayInit(len, POINTER_BYTES);
  for (int i = 0; i < pList->pNodeList->length; i++) {
    SValueNode* valueNode = (SValueNode*)cell->pNode;
    if (!IS_VAR_DATA_TYPE(valueNode->node.resType.type)) {
      terrno = TSDB_CODE_INVALID_PARA;
      taosArrayDestroy(pTbList);
      return NULL;
    }

    char* name = varDataVal(valueNode->datum.p);
    taosArrayPush(pTbList, &name);
    cell = cell->pNext;
  }

  size_t numOfTables = taosArrayGetSize(pTbList);

  // order the name
  taosArraySort(pTbList, nameComparFn);

  // remove the duplicates
  SArray* pNewList = taosArrayInit(taosArrayGetSize(pTbList), sizeof(void*));
  taosArrayPush(pNewList, taosArrayGet(pTbList, 0));

  for (int32_t i = 1; i < numOfTables; ++i) {
    char** name = taosArrayGetLast(pNewList);
    char** nameInOldList = taosArrayGet(pTbList, i);
    if (strcmp(*name, *nameInOldList) == 0) {
      continue;
    }

    taosArrayPush(pNewList, nameInOldList);
  }

  taosArrayDestroy(pTbList);
  return pNewList;
}

dengyihao's avatar
dengyihao 已提交
651
static int tableUidCompare(const void* a, const void* b) {
H
Haojun Liao 已提交
652 653 654
  uint64_t u1 = *(uint64_t*)a;
  uint64_t u2 = *(uint64_t*)b;

dengyihao's avatar
dengyihao 已提交
655 656 657
  if (u1 == u2) {
    return 0;
  }
H
Haojun Liao 已提交
658

dengyihao's avatar
dengyihao 已提交
659 660
  return u1 < u2 ? -1 : 1;
}
H
Haojun Liao 已提交
661

H
Haojun Liao 已提交
662
static int32_t filterTableInfoCompare(const void* a, const void* b) {
663 664
  STUidTagInfo* p1 = (STUidTagInfo*) a;
  STUidTagInfo* p2 = (STUidTagInfo*) b;
H
Haojun Liao 已提交
665 666 667 668 669 670 671 672

  if (p1->uid == p2->uid) {
    return 0;
  }

  return p1->uid < p2->uid? -1:1;
}

673
static int32_t optimizeTbnameInCond(void* metaHandle, int64_t suid, SArray* pRes, SNode* cond) {
dengyihao's avatar
dengyihao 已提交
674
  int32_t ret = -1;
675 676 677
  int32_t ntype = nodeType(cond);

  if (ntype == QUERY_NODE_OPERATOR) {
H
Haojun Liao 已提交
678
    ret = optimizeTbnameInCondImpl(metaHandle, pRes, cond);
dengyihao's avatar
dengyihao 已提交
679 680
  }

681
  if (ntype != QUERY_NODE_LOGIC_CONDITION || ((SLogicConditionNode*)cond)->condType != LOGIC_COND_TYPE_AND) {
dengyihao's avatar
dengyihao 已提交
682
    return ret;
dengyihao's avatar
dengyihao 已提交
683 684
  }

dengyihao's avatar
dengyihao 已提交
685
  bool                 hasTbnameCond = false;
dengyihao's avatar
dengyihao 已提交
686
  SLogicConditionNode* pNode = (SLogicConditionNode*)cond;
dengyihao's avatar
dengyihao 已提交
687
  SNodeList*           pList = (SNodeList*)pNode->pParameterList;
dengyihao's avatar
dengyihao 已提交
688

dengyihao's avatar
dengyihao 已提交
689
  int32_t len = LIST_LENGTH(pList);
H
Haojun Liao 已提交
690 691 692
  if (len <= 0) {
    return ret;
  }
dengyihao's avatar
dengyihao 已提交
693

dengyihao's avatar
dengyihao 已提交
694
  SListCell* cell = pList->pHead;
dengyihao's avatar
dengyihao 已提交
695
  for (int i = 0; i < len; i++) {
dengyihao's avatar
dengyihao 已提交
696
    if (cell == NULL) break;
H
Haojun Liao 已提交
697
    if (optimizeTbnameInCondImpl(metaHandle, pRes, cell->pNode) == 0) {
dengyihao's avatar
dengyihao 已提交
698
      hasTbnameCond = true;
dengyihao's avatar
dengyihao 已提交
699
      break;
dengyihao's avatar
dengyihao 已提交
700 701 702
    }
    cell = cell->pNext;
  }
H
Haojun Liao 已提交
703

H
Haojun Liao 已提交
704 705
  taosArraySort(pRes, filterTableInfoCompare);
  taosArrayRemoveDuplicate(pRes, filterTableInfoCompare, NULL);
dengyihao's avatar
dengyihao 已提交
706

dengyihao's avatar
dengyihao 已提交
707
  if (hasTbnameCond) {
708
    ret = metaGetTableTagsByUids(metaHandle, suid, pRes);
709
//    removeInvalidUid(pRes, tags);
dengyihao's avatar
dengyihao 已提交
710
  }
H
Haojun Liao 已提交
711

dengyihao's avatar
dengyihao 已提交
712 713 714
  return ret;
}

715
#if 0
dengyihao's avatar
dengyihao 已提交
716 717 718
/*
 * handle invalid uid
 */
719 720 721 722 723
static int32_t removeInvalidUid(SArray* uids, SHashObj* tags) {
  int32_t size = taosArrayGetSize(uids);
  if (size <= 0) {
    return 0;
  }
dengyihao's avatar
dengyihao 已提交
724

725
  SArray* validUid = taosArrayInit(size, sizeof(STUidTagInfo));
dengyihao's avatar
dengyihao 已提交
726

727
  for (int32_t i = 0; i < size; i++) {
728
    STUidTagInfo* p = taosArrayGet(uids, i);
H
Haojun Liao 已提交
729 730
    if (taosHashGet(tags, &p->uid, sizeof(int64_t)) != NULL) {
      taosArrayPush(validUid, p);
dengyihao's avatar
dengyihao 已提交
731 732
    }
  }
H
Haojun Liao 已提交
733

dengyihao's avatar
dengyihao 已提交
734 735 736
  taosArraySwap(uids, validUid);
  taosArrayDestroy(validUid);
  return 0;
dengyihao's avatar
dengyihao 已提交
737
}
738

739 740
#endif

741
// only return uid that does not contained in pExistedUidList
H
Haojun Liao 已提交
742
static int32_t optimizeTbnameInCondImpl(void* metaHandle, SArray* pExistedUidList, SNode* pTagCond) {
dengyihao's avatar
dengyihao 已提交
743 744 745
  if (nodeType(pTagCond) != QUERY_NODE_OPERATOR) {
    return -1;
  }
746

dengyihao's avatar
dengyihao 已提交
747 748 749 750
  SOperatorNode* pNode = (SOperatorNode*)pTagCond;
  if (pNode->opType != OP_TYPE_IN) {
    return -1;
  }
751

dengyihao's avatar
dengyihao 已提交
752 753 754 755 756 757
  if ((pNode->pLeft != NULL && nodeType(pNode->pLeft) == QUERY_NODE_COLUMN &&
       ((SColumnNode*)pNode->pLeft)->colType == COLUMN_TYPE_TBNAME) &&
      (pNode->pRight != NULL && nodeType(pNode->pRight) == QUERY_NODE_NODE_LIST)) {
    SNodeListNode* pList = (SNodeListNode*)pNode->pRight;

    int32_t len = LIST_LENGTH(pList->pNodeList);
H
Haojun Liao 已提交
758 759
    if (len <= 0) {
      return -1;
dengyihao's avatar
dengyihao 已提交
760 761
    }

dengyihao's avatar
dengyihao 已提交
762 763 764
    SArray*   pTbList = getTableNameList(pList);
    int32_t   numOfTables = taosArrayGetSize(pTbList);
    SHashObj* uHash = NULL;
H
Haojun Liao 已提交
765

766 767 768 769
    size_t    numOfExisted = taosArrayGetSize(pExistedUidList);  // len > 0 means there already have uids
    if (numOfExisted > 0) {
      uHash = taosHashInit(numOfExisted / 0.7, taosGetDefaultHashFunction(TSDB_DATA_TYPE_BIGINT), false, HASH_NO_LOCK);
      for (int i = 0; i < numOfExisted; i++) {
770
        STUidTagInfo* pTInfo = taosArrayGet(pExistedUidList, i);
H
Haojun Liao 已提交
771
        taosHashPut(uHash, &pTInfo->uid, sizeof(uint64_t), &i, sizeof(i));
D
dapan1121 已提交
772 773
      }
    }
dengyihao's avatar
dengyihao 已提交
774

775 776
    for (int i = 0; i < numOfTables; i++) {
      char* name = taosArrayGetP(pTbList, i);
dengyihao's avatar
dengyihao 已提交
777 778 779

      uint64_t uid = 0;
      if (metaGetTableUidByName(metaHandle, name, &uid) == 0) {
dengyihao's avatar
dengyihao 已提交
780 781
        ETableType tbType = TSDB_TABLE_MAX;
        if (metaGetTableTypeByName(metaHandle, name, &tbType) == 0 && tbType == TSDB_CHILD_TABLE) {
D
dapan1121 已提交
782
          if (NULL == uHash || taosHashGet(uHash, &uid, sizeof(uid)) == NULL) {
783
            STUidTagInfo s = {.uid = uid, .name = name, .pTagVal = NULL};
H
Haojun Liao 已提交
784
            taosArrayPush(pExistedUidList, &s);
D
dapan1121 已提交
785
          }
dengyihao's avatar
dengyihao 已提交
786 787
        } else {
          taosArrayDestroy(pTbList);
D
dapan1121 已提交
788
          taosHashCleanup(uHash);
dengyihao's avatar
dengyihao 已提交
789 790
          return -1;
        }
dengyihao's avatar
dengyihao 已提交
791
      } else {
H
Haojun Liao 已提交
792
//        qWarn("failed to get tableIds from by table name: %s, reason: %s", name, tstrerror(terrno));
dengyihao's avatar
dengyihao 已提交
793 794 795
        terrno = 0;
      }
    }
796

D
dapan1121 已提交
797
    taosHashCleanup(uHash);
dengyihao's avatar
dengyihao 已提交
798
    taosArrayDestroy(pTbList);
dengyihao's avatar
dengyihao 已提交
799
    return 0;
dengyihao's avatar
dengyihao 已提交
800
  }
H
Haojun Liao 已提交
801

dengyihao's avatar
dengyihao 已提交
802
  return -1;
dengyihao's avatar
dengyihao 已提交
803
}
H
Haojun Liao 已提交
804

805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820
static void genTagFilterDigest(const SNode* pTagCond, T_MD5_CTX* pContext) {
  if (pTagCond == NULL) {
    return;
  }

  char*   payload = NULL;
  int32_t len = 0;
  nodesNodeToMsg(pTagCond, &payload, &len);

  tMD5Init(pContext);
  tMD5Update(pContext, (uint8_t*)payload, (uint32_t)len);
  tMD5Final(pContext);

  taosMemoryFree(payload);
}

H
Haojun Liao 已提交
821
static SSDataBlock* createTagValBlockForFilter(SArray* pColList, int32_t numOfTables, SArray* pUidTagList, void* metaHandle) {
822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851
  SSDataBlock* pResBlock = createDataBlock();
  if (pResBlock == NULL) {
    terrno = TSDB_CODE_OUT_OF_MEMORY;
    return NULL;
  }

  for (int32_t i = 0; i < taosArrayGetSize(pColList); ++i) {
    SColumnInfoData colInfo = {0};
    colInfo.info = *(SColumnInfo*)taosArrayGet(pColList, i);
    blockDataAppendColInfo(pResBlock, &colInfo);
  }

  int32_t code = blockDataEnsureCapacity(pResBlock, numOfTables);
  if (code != TSDB_CODE_SUCCESS) {
    terrno = code;
    return NULL;
  }

  pResBlock->info.rows = numOfTables;

  int32_t numOfCols = taosArrayGetSize(pResBlock->pDataBlock);

  for (int32_t i = 0; i < numOfTables; i++) {
    STUidTagInfo* p1 = taosArrayGet(pUidTagList, i);

    for (int32_t j = 0; j < numOfCols; j++) {
      SColumnInfoData* pColInfo = (SColumnInfoData*)taosArrayGet(pResBlock->pDataBlock, j);

      if (pColInfo->info.colId == -1) {  // tbname
        char str[TSDB_TABLE_FNAME_LEN + VARSTR_HEADER_SIZE] = {0};
H
Haojun Liao 已提交
852 853 854 855 856 857
        if (p1->name != NULL) {
          STR_TO_VARSTR(str, p1->name);
        } else { // name is not retrieved during filter
          metaGetTableNameByUid(metaHandle, p1->uid, str);
        }

858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915
        colDataAppend(pColInfo, i, str, false);
#if TAG_FILTER_DEBUG
        qDebug("tagfilter uid:%ld, tbname:%s", *uid, str + 2);
#endif
      } else {
        STagVal tagVal = {0};
        tagVal.cid = pColInfo->info.colId;
        if (p1->pTagVal == NULL) {
          colDataAppendNULL(pColInfo, i);
        }

        const char* p = metaGetTableTagVal(p1->pTagVal, pColInfo->info.type, &tagVal);

        if (p == NULL || (pColInfo->info.type == TSDB_DATA_TYPE_JSON && ((STag*)p)->nTag == 0)) {
          colDataAppendNULL(pColInfo, i);
        } else if (pColInfo->info.type == TSDB_DATA_TYPE_JSON) {
          colDataAppend(pColInfo, i, p, false);
        } else if (IS_VAR_DATA_TYPE(pColInfo->info.type)) {
          char* tmp = alloca(tagVal.nData + VARSTR_HEADER_SIZE + 1);
          varDataSetLen(tmp, tagVal.nData);
          memcpy(tmp + VARSTR_HEADER_SIZE, tagVal.pData, tagVal.nData);
          colDataAppend(pColInfo, i, tmp, false);
#if TAG_FILTER_DEBUG
          qDebug("tagfilter varch:%s", tmp + 2);
#endif
        } else {
          colDataAppend(pColInfo, i, (const char*)&tagVal.i64, false);
#if TAG_FILTER_DEBUG
          if (pColInfo->info.type == TSDB_DATA_TYPE_INT) {
            qDebug("tagfilter int:%d", *(int*)(&tagVal.i64));
          } else if (pColInfo->info.type == TSDB_DATA_TYPE_DOUBLE) {
            qDebug("tagfilter double:%f", *(double*)(&tagVal.i64));
          }
#endif
        }
      }
    }
  }

  return pResBlock;
}

static void doSetQualifiedUid(SArray* pUidList, const SArray* pUidTagList, bool* pResultList) {
  taosArrayClear(pUidList);

  int32_t numOfTables = taosArrayGetSize(pUidTagList);
  for(int32_t i = 0; i < numOfTables; ++i) {
    uint64_t uid = ((STUidTagInfo*)taosArrayGet(pUidTagList, i))->uid;
    qDebug("tagfilter get uid:%" PRId64 ", res:%d", uid, pResultList[i]);

    if (pResultList[i]) {
      taosArrayPush(pUidList, &uid);
    }
  }
}

static void copyExistedUids(SArray* pUidTagList, const SArray* pUidList) {
  int32_t numOfExisted = taosArrayGetSize(pUidList);
916 917 918 919 920 921 922 923
  if (numOfExisted == 0) {
    return;
  }

  for(int32_t i = 0; i < numOfExisted; ++i) {
    uint64_t* uid = taosArrayGet(pUidList, i);
    STUidTagInfo info = {.uid = *uid};
    taosArrayPush(pUidTagList, &info);
924 925 926 927
  }
}

static int32_t doFilterByTagCond(STableListInfo* pListInfo, SArray* pUidList, SNode* pTagCond, void* metaHandle) {
928 929 930 931 932
  if (pTagCond == NULL) {
    return TSDB_CODE_SUCCESS;
  }

  terrno = TDB_CODE_SUCCESS;
933 934 935 936 937 938 939 940 941 942 943

  int32_t      code = TSDB_CODE_SUCCESS;
  SArray*      pBlockList = NULL;
  SSDataBlock* pResBlock = NULL;
  SScalarParam output = {0};

  tagFilterAssist ctx = {0};
  ctx.colHash = taosHashInit(4, taosGetDefaultHashFunction(TSDB_DATA_TYPE_SMALLINT), false, HASH_NO_LOCK);
  if (ctx.colHash == NULL) {
    terrno = TSDB_CODE_OUT_OF_MEMORY;
    goto end;
944 945
  }

946 947 948 949 950
  ctx.cInfoList = taosArrayInit(4, sizeof(SColumnInfo));
  if (ctx.cInfoList == NULL) {
    terrno = TSDB_CODE_OUT_OF_MEMORY;
    goto end;
  }
951

952
  nodesRewriteExprPostOrder(&pTagCond, getColumn, (void*)&ctx);
953

954
  SDataType type = {.type = TSDB_DATA_TYPE_BOOL, .bytes = sizeof(bool)};
955

956 957
  //  int64_t stt = taosGetTimestampUs();
  SArray* pUidTagList = taosArrayInit(10, sizeof(STUidTagInfo));
958 959
  copyExistedUids(pUidTagList, pUidList);

960 961
  int32_t filter = optimizeTbnameInCond(metaHandle, pListInfo->suid, pUidTagList, pTagCond);
  if (filter == 0) {  // tbname in filter is activated, do nothing and return
962 963
    taosArrayClear(pUidList);

964 965 966 967 968 969
    int32_t numOfRows = taosArrayGetSize(pUidTagList);
    taosArrayEnsureCap(pUidList, numOfRows);
    for(int32_t i = 0; i < numOfRows; ++i) {
      STUidTagInfo* pInfo = taosArrayGet(pUidTagList, i);
      taosArrayPush(pUidList, &pInfo->uid);
    }
H
Haojun Liao 已提交
970

971 972 973 974 975 976 977 978 979
    terrno = 0;
    goto end;
  } else {
    // here we retrieve all tags from the vnode table-meta store
    code = metaGetTableTags(metaHandle, pListInfo->suid, pUidTagList);
    if (code != TSDB_CODE_SUCCESS) {
      qError("failed to get table tags from meta, reason:%s, suid:%" PRIu64, tstrerror(code), pListInfo->suid);
      terrno = code;
      goto end;
980
    }
981
  }
982

983 984 985
  int32_t numOfTables = taosArrayGetSize(pUidTagList);
  if (numOfTables == 0) {
    goto end;
986 987
  }

H
Haojun Liao 已提交
988 989 990
  pResBlock = createTagValBlockForFilter(ctx.cInfoList, numOfTables, pUidTagList, metaHandle);
  if (pResBlock == NULL) {
    code = terrno;
991 992 993 994 995 996 997 998 999 1000
    goto end;
  }

  //  int64_t st1 = taosGetTimestampUs();
  //  qDebug("generate tag block rows:%d, cost:%ld us", rows, st1-st);
  pBlockList = taosArrayInit(2, POINTER_BYTES);
  taosArrayPush(pBlockList, &pResBlock);

  code = createResultData(&type, numOfTables, &output);
  if (code != TSDB_CODE_SUCCESS) {
H
Haojun Liao 已提交
1001
    terrno = code;
1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018
    goto end;
  }

  code = scalarCalculate(pTagCond, pBlockList, &output);
  if (code != TSDB_CODE_SUCCESS) {
    qError("failed to calculate scalar, reason:%s", tstrerror(code));
    terrno = code;
    goto end;
  }

  doSetQualifiedUid(pUidList, pUidTagList, (bool*) output.columnData->pData);

  end:
  taosHashCleanup(ctx.colHash);
  taosArrayDestroy(ctx.cInfoList);
  blockDataDestroy(pResBlock);
  taosArrayDestroy(pBlockList);
H
Haojun Liao 已提交
1019
  taosArrayDestroyEx(pUidTagList, freeItem);
1020 1021 1022

  colDataDestroy(output.columnData);
  taosMemoryFreeClear(output.columnData);
H
Haojun Liao 已提交
1023
  return code;
1024 1025
}

1026
int32_t getTableList(void* metaHandle, void* pVnode, SScanPhysiNode* pScanNode, SNode* pTagCond, SNode* pTagIndexCond,
1027
                     STableListInfo* pListInfo, const char* idstr) {
1028
  int32_t code = TSDB_CODE_SUCCESS;
1029
  size_t  numOfTables = 0;
1030

D
dapan1121 已提交
1031
  pListInfo->suid = pScanNode->suid;
1032
  SArray* pUidList = taosArrayInit(8, sizeof(uint64_t));
dengyihao's avatar
dengyihao 已提交
1033

1034
  if (pScanNode->tableType != TSDB_SUPER_TABLE) {
1035 1036
    if (metaIsTableExist(metaHandle, pScanNode->uid)) {
      taosArrayPush(pUidList, &pScanNode->uid);
1037
    }
1038

1039
    code = doFilterByTagCond(pListInfo, pUidList, pTagCond, metaHandle);
1040
    if (code != TSDB_CODE_SUCCESS) {
H
Haojun Liao 已提交
1041
      goto _end;
H
Haojun Liao 已提交
1042
    }
1043 1044
  } else {
    T_MD5_CTX context = {0};
H
Haojun Liao 已提交
1045

1046 1047 1048 1049 1050
    if (tsTagFilterCache) {
      // try to retrieve the result from meta cache
      genTagFilterDigest(pTagCond, &context);

      bool acquired = false;
1051
      metaGetCachedTableUidList(metaHandle, pScanNode->suid, context.digest, tListLen(context.digest), pUidList, &acquired);
1052
      if (acquired) {
1053
        qDebug("retrieve table uid list from cache, numOfTables:%d", (int32_t)taosArrayGetSize(pUidList));
1054 1055
        goto _end;
      }
wmmhello's avatar
wmmhello 已提交
1056 1057
    }

1058
    if (!pTagCond) {  // no tag filter condition exists, let's fetch all tables of this super table
1059
      ASSERT(pTagIndexCond == NULL);
1060
      vnodeGetCtbIdList(pVnode, pScanNode->suid, pUidList);
1061
    } else {
H
Haojun Liao 已提交
1062 1063
      // failed to find the result in the cache, let try to calculate the results
      if (pTagIndexCond) {
1064 1065 1066
        void* pIndex = tsdbGetIvtIdx(metaHandle);
        SIndexMetaArg metaArg = {
            .metaEx = metaHandle, .idx = tsdbGetIdx(metaHandle), .ivtIdx = pIndex, .suid = pScanNode->uid};
H
Haojun Liao 已提交
1067 1068

        SIdxFltStatus status = SFLT_NOT_INDEX;
1069
        code = doFilterTag(pTagIndexCond, &metaArg, pUidList, &status);
H
Haojun Liao 已提交
1070 1071
        if (code != 0 || status == SFLT_NOT_INDEX) {  // temporarily disable it for performance sake
//          qError("failed to get tableIds from index, reason:%s, suid:%" PRIu64, tstrerror(code), tableUid);
H
Haojun Liao 已提交
1072 1073
          code = TDB_CODE_SUCCESS;
        }
wmmhello's avatar
wmmhello 已提交
1074 1075
      }
    }
1076

1077
    code = doFilterByTagCond(pListInfo, pUidList, pTagCond, metaHandle);
1078
    if (code != TSDB_CODE_SUCCESS) {
H
Haojun Liao 已提交
1079
      goto _end;
wmmhello's avatar
wmmhello 已提交
1080 1081
    }

1082
    // let's add the filter results into meta-cache
1083
    numOfTables = taosArrayGetSize(pUidList);
1084

1085
    if (tsTagFilterCache) {
1086 1087 1088 1089 1090
      size_t size = numOfTables * sizeof(uint64_t) + sizeof(int32_t);
      char*  pPayload = taosMemoryMalloc(size);

      if (numOfTables > 0) {
        *(int32_t*)pPayload = numOfTables;
1091
        memcpy(pPayload + sizeof(int32_t), taosArrayGet(pUidList, 0), numOfTables * sizeof(uint64_t));
1092 1093
      }

1094
      metaUidFilterCachePut(metaHandle, pScanNode->suid, context.digest, tListLen(context.digest), pPayload, size, 1);
1095
      taosMemoryFree(pPayload);
1096
    }
wmmhello's avatar
wmmhello 已提交
1097 1098
  }

1099
_end:
1100
  numOfTables = taosArrayGetSize(pUidList);
H
Haojun Liao 已提交
1101
  for (int i = 0; i < numOfTables; i++) {
1102
    STableKeyInfo info = {.uid = *(uint64_t*)taosArrayGet(pUidList, i), .groupId = 0};
1103 1104

    void* p = taosArrayPush(pListInfo->pTableList, &info);
H
Haojun Liao 已提交
1105
    if (p == NULL) {
1106
      taosArrayDestroy(pUidList);
H
Haojun Liao 已提交
1107 1108 1109
      return TSDB_CODE_OUT_OF_MEMORY;
    }

1110
    qTrace("tagfilter get uid:%" PRIu64", %s", info.uid, idstr);
1111 1112
  }

1113
  taosArrayDestroy(pUidList);
1114 1115
  return code;
}
H
Haojun Liao 已提交
1116

1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129
size_t getTableTagsBufLen(const SNodeList* pGroups) {
  size_t keyLen = 0;

  SNode* node;
  FOREACH(node, pGroups) {
    SExprNode* pExpr = (SExprNode*)node;
    keyLen += pExpr->resType.bytes;
  }

  keyLen += sizeof(int8_t) * LIST_LENGTH(pGroups);
  return keyLen;
}

H
Haojun Liao 已提交
1130
int32_t getGroupIdFromTagsVal(void* pMeta, uint64_t uid, SNodeList* pGroupNode, char* keyBuf, uint64_t* pGroupId) {
M
Minglei Jin 已提交
1131
  SMetaReader mr = {0};
1132
  metaReaderInit(&mr, pMeta, 0);
H
Haojun Liao 已提交
1133
  if (metaGetTableEntryByUidCache(&mr, uid) != 0) {  // table not exist
1134 1135 1136
    metaReaderClear(&mr);
    return TSDB_CODE_PAR_TABLE_NOT_EXIST;
  }
1137 1138 1139 1140 1141

  SNodeList* groupNew = nodesCloneList(pGroupNode);

  nodesRewriteExprsPostOrder(groupNew, doTranslateTagExpr, &mr);
  char* isNull = (char*)keyBuf;
M
Minglei Jin 已提交
1142
  char* pStart = (char*)keyBuf + sizeof(int8_t) * LIST_LENGTH(pGroupNode);
1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157

  SNode*  pNode;
  int32_t index = 0;
  FOREACH(pNode, groupNew) {
    SNode*  pNew = NULL;
    int32_t code = scalarCalculateConstants(pNode, &pNew);
    if (TSDB_CODE_SUCCESS == code) {
      REPLACE_NODE(pNew);
    } else {
      taosMemoryFree(keyBuf);
      nodesDestroyList(groupNew);
      metaReaderClear(&mr);
      return code;
    }

1158
    ASSERT(nodeType(pNew) == QUERY_NODE_VALUE);
1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187
    SValueNode* pValue = (SValueNode*)pNew;

    if (pValue->node.resType.type == TSDB_DATA_TYPE_NULL || pValue->isNull) {
      isNull[index++] = 1;
      continue;
    } else {
      isNull[index++] = 0;
      char* data = nodesGetValueFromNode(pValue);
      if (pValue->node.resType.type == TSDB_DATA_TYPE_JSON) {
        if (tTagIsJson(data)) {
          terrno = TSDB_CODE_QRY_JSON_IN_GROUP_ERROR;
          taosMemoryFree(keyBuf);
          nodesDestroyList(groupNew);
          metaReaderClear(&mr);
          return terrno;
        }
        int32_t len = getJsonValueLen(data);
        memcpy(pStart, data, len);
        pStart += len;
      } else if (IS_VAR_DATA_TYPE(pValue->node.resType.type)) {
        memcpy(pStart, data, varDataTLen(data));
        pStart += varDataTLen(data);
      } else {
        memcpy(pStart, data, pValue->node.resType.bytes);
        pStart += pValue->node.resType.bytes;
      }
    }
  }

M
Minglei Jin 已提交
1188
  int32_t len = (int32_t)(pStart - (char*)keyBuf);
1189 1190 1191 1192 1193 1194 1195
  *pGroupId = calcGroupId(keyBuf, len);

  nodesDestroyList(groupNew);
  metaReaderClear(&mr);
  return TSDB_CODE_SUCCESS;
}

1196
SArray* extractPartitionColInfo(SNodeList* pNodeList) {
dengyihao's avatar
dengyihao 已提交
1197
  if (!pNodeList) {
1198 1199
    return NULL;
  }
H
Haojun Liao 已提交
1200

1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221
  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) {
    SColumnNode* pColNode = (SColumnNode*)nodesListGetNode(pNodeList, i);

    // todo extract method
    SColumn c = {0};
    c.slotId = pColNode->slotId;
    c.colId = pColNode->colId;
    c.type = pColNode->node.resType.type;
    c.bytes = pColNode->node.resType.bytes;
    c.precision = pColNode->node.resType.precision;
    c.scale = pColNode->node.resType.scale;

    taosArrayPush(pList, &c);
  }
H
Haojun Liao 已提交
1222

1223
  return pList;
H
Haojun Liao 已提交
1224 1225
}

H
Haojun Liao 已提交
1226 1227
int32_t extractColMatchInfo(SNodeList* pNodeList, SDataBlockDescNode* pOutputNodeList, int32_t* numOfOutputCols,
                            int32_t type, SColMatchInfo* pMatchInfo) {
H
Haojun Liao 已提交
1228
  size_t  numOfCols = LIST_LENGTH(pNodeList);
H
Haojun Liao 已提交
1229 1230 1231 1232
  int32_t code = 0;

  pMatchInfo->matchType = type;

1233
  SArray* pList = taosArrayInit(numOfCols, sizeof(SColMatchItem));
1234
  if (pList == NULL) {
H
Haojun Liao 已提交
1235 1236
    code = TSDB_CODE_OUT_OF_MEMORY;
    return code;
1237 1238 1239 1240
  }

  for (int32_t i = 0; i < numOfCols; ++i) {
    STargetNode* pNode = (STargetNode*)nodesListGetNode(pNodeList, i);
1241 1242 1243
    if (nodeType(pNode->pExpr) == QUERY_NODE_COLUMN) {
      SColumnNode* pColNode = (SColumnNode*)pNode->pExpr;

H
Haojun Liao 已提交
1244
      SColMatchItem c = {.needOutput = true};
1245 1246
      c.colId = pColNode->colId;
      c.srcSlotId = pColNode->slotId;
H
Haojun Liao 已提交
1247
      c.dstSlotId = pNode->slotId;
1248 1249
      taosArrayPush(pList, &c);
    }
1250 1251
  }

H
Haojun Liao 已提交
1252
  // set the output flag for each column in SColMatchInfo, according to the
1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264
  *numOfOutputCols = 0;
  int32_t num = LIST_LENGTH(pOutputNodeList->pSlots);
  for (int32_t i = 0; i < num; ++i) {
    SSlotDescNode* pNode = (SSlotDescNode*)nodesListGetNode(pOutputNodeList->pSlots, i);

    // todo: add reserve flag check
    // it is a column reserved for the arithmetic expression calculation
    if (pNode->slotId >= numOfCols) {
      (*numOfOutputCols) += 1;
      continue;
    }

H
Haojun Liao 已提交
1265
    SColMatchItem* info = NULL;
1266 1267
    for (int32_t j = 0; j < taosArrayGetSize(pList); ++j) {
      info = taosArrayGet(pList, j);
H
Haojun Liao 已提交
1268
      if (info->dstSlotId == pNode->slotId) {
1269 1270 1271
        break;
      }
    }
1272

1273 1274
    if (pNode->output) {
      (*numOfOutputCols) += 1;
H
Haojun Liao 已提交
1275 1276
    } else if (info != NULL) {
      // select distinct tbname from stb where tbname='abc';
H
Haojun Liao 已提交
1277
      info->needOutput = false;
1278
    }
1279
  }
1280

H
Haojun Liao 已提交
1281
  pMatchInfo->pList = pList;
H
Haojun Liao 已提交
1282
  return code;
1283 1284
}

1285 1286 1287 1288 1289 1290 1291 1292
static SResSchema createResSchema(int32_t type, int32_t bytes, int32_t slotId, int32_t scale, int32_t precision,
                                  const char* name) {
  SResSchema s = {0};
  s.scale = scale;
  s.type = type;
  s.bytes = bytes;
  s.slotId = slotId;
  s.precision = precision;
H
Haojun Liao 已提交
1293
  tstrncpy(s.name, name, tListLen(s.name));
1294 1295 1296

  return s;
}
1297

H
Haojun Liao 已提交
1298
static SColumn* createColumn(int32_t blockId, int32_t slotId, int32_t colId, SDataType* pType, EColumnType colType) {
1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311
  SColumn* pCol = taosMemoryCalloc(1, sizeof(SColumn));
  if (pCol == NULL) {
    terrno = TSDB_CODE_OUT_OF_MEMORY;
    return NULL;
  }

  pCol->slotId = slotId;
  pCol->colId = colId;
  pCol->bytes = pType->bytes;
  pCol->type = pType->type;
  pCol->scale = pType->scale;
  pCol->precision = pType->precision;
  pCol->dataBlockId = blockId;
H
Haojun Liao 已提交
1312
  pCol->colType = colType;
1313 1314 1315
  return pCol;
}

1316
void createExprFromOneNode(SExprInfo* pExp, SNode* pNode, int16_t slotId) {
1317 1318 1319 1320
  pExp->pExpr = taosMemoryCalloc(1, sizeof(tExprNode));
  pExp->pExpr->_function.num = 1;
  pExp->pExpr->_function.functionId = -1;

1321
  int32_t type = nodeType(pNode);
1322 1323 1324
  // it is a project query, or group by column
  if (type == QUERY_NODE_COLUMN) {
    pExp->pExpr->nodeType = QUERY_NODE_COLUMN;
1325
    SColumnNode* pColNode = (SColumnNode*)pNode;
1326 1327 1328 1329 1330

    pExp->base.pParam = taosMemoryCalloc(1, sizeof(SFunctParam));
    pExp->base.numOfParams = 1;

    SDataType* pType = &pColNode->node.resType;
1331 1332
    pExp->base.resSchema =
        createResSchema(pType->type, pType->bytes, slotId, pType->scale, pType->precision, pColNode->colName);
1333 1334 1335 1336 1337
    pExp->base.pParam[0].pCol =
        createColumn(pColNode->dataBlockId, pColNode->slotId, pColNode->colId, pType, pColNode->colType);
    pExp->base.pParam[0].type = FUNC_PARAM_TYPE_COLUMN;
  } else if (type == QUERY_NODE_VALUE) {
    pExp->pExpr->nodeType = QUERY_NODE_VALUE;
1338
    SValueNode* pValNode = (SValueNode*)pNode;
1339 1340 1341 1342 1343

    pExp->base.pParam = taosMemoryCalloc(1, sizeof(SFunctParam));
    pExp->base.numOfParams = 1;

    SDataType* pType = &pValNode->node.resType;
1344 1345
    pExp->base.resSchema =
        createResSchema(pType->type, pType->bytes, slotId, pType->scale, pType->precision, pValNode->node.aliasName);
1346 1347 1348 1349
    pExp->base.pParam[0].type = FUNC_PARAM_TYPE_VALUE;
    nodesValueNodeToVariant(pValNode, &pExp->base.pParam[0].param);
  } else if (type == QUERY_NODE_FUNCTION) {
    pExp->pExpr->nodeType = QUERY_NODE_FUNCTION;
1350
    SFunctionNode* pFuncNode = (SFunctionNode*)pNode;
1351 1352

    SDataType* pType = &pFuncNode->node.resType;
1353 1354
    pExp->base.resSchema =
        createResSchema(pType->type, pType->bytes, slotId, pType->scale, pType->precision, pFuncNode->node.aliasName);
1355

H
Haojun Liao 已提交
1356 1357 1358 1359
    tExprNode* pExprNode = pExp->pExpr;

    pExprNode->_function.functionId = pFuncNode->funcId;
    pExprNode->_function.pFunctNode = pFuncNode;
S
shenglian zhou 已提交
1360
    pExprNode->_function.functionType = pFuncNode->funcType;
H
Haojun Liao 已提交
1361 1362

    tstrncpy(pExprNode->_function.functionName, pFuncNode->functionName, tListLen(pExprNode->_function.functionName));
1363 1364 1365

#if 1
    // todo refactor: add the parameter for tbname function
H
Haojun Liao 已提交
1366
    const char* name = "tbname";
dengyihao's avatar
dengyihao 已提交
1367
    int32_t     len = strlen(name);
H
Haojun Liao 已提交
1368 1369 1370

    if (!pFuncNode->pParameterList && (memcmp(pExprNode->_function.functionName, name, len) == 0) &&
        pExprNode->_function.functionName[len] == 0) {
1371
      pFuncNode->pParameterList = nodesMakeList();
1372
      ASSERT(LIST_LENGTH(pFuncNode->pParameterList) == 0);
1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402
      SValueNode* res = (SValueNode*)nodesMakeNode(QUERY_NODE_VALUE);
      if (NULL == res) {  // todo handle error
      } else {
        res->node.resType = (SDataType){.bytes = sizeof(int64_t), .type = TSDB_DATA_TYPE_BIGINT};
        nodesListAppend(pFuncNode->pParameterList, (SNode*)res);
      }
    }
#endif

    int32_t numOfParam = LIST_LENGTH(pFuncNode->pParameterList);

    pExp->base.pParam = taosMemoryCalloc(numOfParam, sizeof(SFunctParam));
    pExp->base.numOfParams = numOfParam;

    for (int32_t j = 0; j < numOfParam; ++j) {
      SNode* p1 = nodesListGetNode(pFuncNode->pParameterList, j);
      if (p1->type == QUERY_NODE_COLUMN) {
        SColumnNode* pcn = (SColumnNode*)p1;

        pExp->base.pParam[j].type = FUNC_PARAM_TYPE_COLUMN;
        pExp->base.pParam[j].pCol =
            createColumn(pcn->dataBlockId, pcn->slotId, pcn->colId, &pcn->node.resType, pcn->colType);
      } else if (p1->type == QUERY_NODE_VALUE) {
        SValueNode* pvn = (SValueNode*)p1;
        pExp->base.pParam[j].type = FUNC_PARAM_TYPE_VALUE;
        nodesValueNodeToVariant(pvn, &pExp->base.pParam[j].param);
      }
    }
  } else if (type == QUERY_NODE_OPERATOR) {
    pExp->pExpr->nodeType = QUERY_NODE_OPERATOR;
1403
    SOperatorNode* pOpNode = (SOperatorNode*)pNode;
1404 1405 1406 1407

    pExp->base.pParam = taosMemoryCalloc(1, sizeof(SFunctParam));
    pExp->base.numOfParams = 1;

1408 1409 1410 1411
    SDataType* pType = &pOpNode->node.resType;
    pExp->base.resSchema =
        createResSchema(pType->type, pType->bytes, slotId, pType->scale, pType->precision, pOpNode->node.aliasName);
    pExp->pExpr->_optrRoot.pRootNode = pNode;
D
dapan1121 已提交
1412 1413
  } else if (type == QUERY_NODE_CASE_WHEN) {
    pExp->pExpr->nodeType = QUERY_NODE_OPERATOR;
D
dapan1121 已提交
1414
    SCaseWhenNode* pCaseNode = (SCaseWhenNode*)pNode;
dengyihao's avatar
dengyihao 已提交
1415

D
dapan1121 已提交
1416 1417
    pExp->base.pParam = taosMemoryCalloc(1, sizeof(SFunctParam));
    pExp->base.numOfParams = 1;
dengyihao's avatar
dengyihao 已提交
1418

D
dapan1121 已提交
1419
    SDataType* pType = &pCaseNode->node.resType;
dengyihao's avatar
dengyihao 已提交
1420 1421
    pExp->base.resSchema =
        createResSchema(pType->type, pType->bytes, slotId, pType->scale, pType->precision, pCaseNode->node.aliasName);
D
dapan1121 已提交
1422
    pExp->pExpr->_optrRoot.pRootNode = pNode;
1423
  } else {
1424
    ASSERT(0);
1425 1426 1427
  }
}

1428 1429 1430 1431
void createExprFromTargetNode(SExprInfo* pExp, STargetNode* pTargetNode) {
  createExprFromOneNode(pExp, pTargetNode->pExpr, pTargetNode->slotId);
}

1432 1433 1434 1435 1436 1437 1438 1439
SExprInfo* createExprInfo(SNodeList* pNodeList, SNodeList* pGroupKeys, int32_t* numOfExprs) {
  int32_t numOfFuncs = LIST_LENGTH(pNodeList);
  int32_t numOfGroupKeys = 0;
  if (pGroupKeys != NULL) {
    numOfGroupKeys = LIST_LENGTH(pGroupKeys);
  }

  *numOfExprs = numOfFuncs + numOfGroupKeys;
1440 1441 1442 1443
  if (*numOfExprs == 0) {
    return NULL;
  }

1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454
  SExprInfo* pExprs = taosMemoryCalloc(*numOfExprs, sizeof(SExprInfo));

  for (int32_t i = 0; i < (*numOfExprs); ++i) {
    STargetNode* pTargetNode = NULL;
    if (i < numOfFuncs) {
      pTargetNode = (STargetNode*)nodesListGetNode(pNodeList, i);
    } else {
      pTargetNode = (STargetNode*)nodesListGetNode(pGroupKeys, i - numOfFuncs);
    }

    SExprInfo* pExp = &pExprs[i];
1455
    createExprFromTargetNode(pExp, pTargetNode);
1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467
  }

  return pExprs;
}

// set the output buffer for the selectivity + tag query
static int32_t setSelectValueColumnInfo(SqlFunctionCtx* pCtx, int32_t numOfOutput) {
  int32_t num = 0;

  SqlFunctionCtx*  p = NULL;
  SqlFunctionCtx** pValCtx = taosMemoryCalloc(numOfOutput, POINTER_BYTES);
  if (pValCtx == NULL) {
S
Shengliang Guan 已提交
1468
    return TSDB_CODE_OUT_OF_MEMORY;
1469 1470 1471
  }

  for (int32_t i = 0; i < numOfOutput; ++i) {
H
Haojun Liao 已提交
1472
    const char* pName = pCtx[i].pExpr->pExpr->_function.functionName;
1473
    if ((strcmp(pName, "_select_value") == 0) || (strcmp(pName, "_group_key") == 0)) {
1474 1475 1476 1477 1478
      pValCtx[num++] = &pCtx[i];
    } else if (fmIsSelectFunc(pCtx[i].functionId)) {
      p = &pCtx[i];
    }
  }
H
Haojun Liao 已提交
1479

1480 1481 1482
  if (p != NULL) {
    p->subsidiaries.pCtx = pValCtx;
    p->subsidiaries.num = num;
1483
  } else {
1484
    taosMemoryFreeClear(pValCtx);
1485
  }
1486 1487

  return TSDB_CODE_SUCCESS;
1488 1489
}

1490
SqlFunctionCtx* createSqlFunctionCtx(SExprInfo* pExprInfo, int32_t numOfOutput, int32_t** rowEntryInfoOffset) {
1491 1492 1493 1494
  SqlFunctionCtx* pFuncCtx = (SqlFunctionCtx*)taosMemoryCalloc(numOfOutput, sizeof(SqlFunctionCtx));
  if (pFuncCtx == NULL) {
    return NULL;
  }
1495

1496 1497
  *rowEntryInfoOffset = taosMemoryCalloc(numOfOutput, sizeof(int32_t));
  if (*rowEntryInfoOffset == 0) {
1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513
    taosMemoryFreeClear(pFuncCtx);
    return NULL;
  }

  for (int32_t i = 0; i < numOfOutput; ++i) {
    SExprInfo* pExpr = &pExprInfo[i];

    SExprBasicInfo* pFunct = &pExpr->base;
    SqlFunctionCtx* pCtx = &pFuncCtx[i];

    pCtx->functionId = -1;
    pCtx->pExpr = pExpr;

    if (pExpr->pExpr->nodeType == QUERY_NODE_FUNCTION) {
      SFuncExecEnv env = {0};
      pCtx->functionId = pExpr->pExpr->_function.pFunctNode->funcId;
1514
      pCtx->isPseudoFunc = fmIsWindowPseudoColumnFunc(pCtx->functionId);
1515
      pCtx->isNotNullFunc = fmIsNotNullOutputFunc(pCtx->functionId);
1516 1517 1518 1519 1520 1521 1522

      if (fmIsAggFunc(pCtx->functionId) || fmIsIndefiniteRowsFunc(pCtx->functionId)) {
        bool isUdaf = fmIsUserDefinedFunc(pCtx->functionId);
        if (!isUdaf) {
          fmGetFuncExecFuncs(pCtx->functionId, &pCtx->fpSet);
        } else {
          char* udfName = pExpr->pExpr->_function.pFunctNode->functionName;
1523
          pCtx->udfName = strdup(udfName);
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
          fmGetUdafExecFuncs(pCtx->functionId, &pCtx->fpSet);
        }
        pCtx->fpSet.getEnv(pExpr->pExpr->_function.pFunctNode, &env);
      } else {
        fmGetScalarFuncExecFuncs(pCtx->functionId, &pCtx->sfp);
        if (pCtx->sfp.getEnv != NULL) {
          pCtx->sfp.getEnv(pExpr->pExpr->_function.pFunctNode, &env);
        }
      }
      pCtx->resDataInfo.interBufSize = env.calcMemSize;
    } else if (pExpr->pExpr->nodeType == QUERY_NODE_COLUMN || pExpr->pExpr->nodeType == QUERY_NODE_OPERATOR ||
               pExpr->pExpr->nodeType == QUERY_NODE_VALUE) {
      // for simple column, the result buffer needs to hold at least one element.
      pCtx->resDataInfo.interBufSize = pFunct->resSchema.bytes;
    }

    pCtx->input.numOfInputCols = pFunct->numOfParams;
    pCtx->input.pData = taosMemoryCalloc(pFunct->numOfParams, POINTER_BYTES);
    pCtx->input.pColumnDataAgg = taosMemoryCalloc(pFunct->numOfParams, POINTER_BYTES);

    pCtx->pTsOutput = NULL;
    pCtx->resDataInfo.bytes = pFunct->resSchema.bytes;
    pCtx->resDataInfo.type = pFunct->resSchema.type;
    pCtx->order = TSDB_ORDER_ASC;
    pCtx->start.key = INT64_MIN;
    pCtx->end.key = INT64_MIN;
    pCtx->numOfParams = pExpr->base.numOfParams;
    pCtx->param = pFunct->pParam;
1552
    pCtx->saveHandle.currentPage = -1;
1553 1554 1555
  }

  for (int32_t i = 1; i < numOfOutput; ++i) {
dengyihao's avatar
dengyihao 已提交
1556 1557
    (*rowEntryInfoOffset)[i] = (int32_t)((*rowEntryInfoOffset)[i - 1] + sizeof(SResultRowEntryInfo) +
                                         pFuncCtx[i - 1].resDataInfo.interBufSize);
1558 1559 1560 1561
  }

  setSelectValueColumnInfo(pFuncCtx, numOfOutput);
  return pFuncCtx;
1562
}
1563 1564

// NOTE: sources columns are more than the destination SSDatablock columns.
1565 1566
// doFilter in table scan needs every column even its output is false
void relocateColumnData(SSDataBlock* pBlock, const SArray* pColMatchInfo, SArray* pCols, bool outputEveryColumn) {
1567 1568 1569 1570 1571
  size_t numOfSrcCols = taosArrayGetSize(pCols);

  int32_t i = 0, j = 0;
  while (i < numOfSrcCols && j < taosArrayGetSize(pColMatchInfo)) {
    SColumnInfoData* p = taosArrayGet(pCols, i);
H
Haojun Liao 已提交
1572
    SColMatchItem*   pmInfo = taosArrayGet(pColMatchInfo, j);
1573 1574

    if (p->info.colId == pmInfo->colId) {
H
Haojun Liao 已提交
1575
      SColumnInfoData* pDst = taosArrayGet(pBlock->pDataBlock, pmInfo->dstSlotId);
1576
      colDataAssign(pDst, p, pBlock->info.rows, &pBlock->info);
1577 1578 1579 1580 1581
      i++;
      j++;
    } else if (p->info.colId < pmInfo->colId) {
      i++;
    } else {
1582
      ASSERT(0);
1583 1584 1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 1599 1600
    }
  }
}

SInterval extractIntervalInfo(const STableScanPhysiNode* pTableScanNode) {
  SInterval interval = {
      .interval = pTableScanNode->interval,
      .sliding = pTableScanNode->sliding,
      .intervalUnit = pTableScanNode->intervalUnit,
      .slidingUnit = pTableScanNode->slidingUnit,
      .offset = pTableScanNode->offset,
  };

  return interval;
}

SColumn extractColumnFromColumnNode(SColumnNode* pColNode) {
  SColumn c = {0};
H
Haojun Liao 已提交
1601

1602 1603 1604 1605 1606
  c.slotId = pColNode->slotId;
  c.colId = pColNode->colId;
  c.type = pColNode->node.resType.type;
  c.bytes = pColNode->node.resType.bytes;
  c.scale = pColNode->node.resType.scale;
1607 1608 1609 1610 1611 1612 1613
  c.precision = pColNode->node.resType.precision;
  return c;
}

int32_t initQueryTableDataCond(SQueryTableDataCond* pCond, const STableScanPhysiNode* pTableScanNode) {
  pCond->order = pTableScanNode->scanSeq[0] > 0 ? TSDB_ORDER_ASC : TSDB_ORDER_DESC;
  pCond->numOfCols = LIST_LENGTH(pTableScanNode->scan.pScanCols);
H
Haojun Liao 已提交
1614

1615
  pCond->colList = taosMemoryCalloc(pCond->numOfCols, sizeof(SColumnInfo));
dengyihao's avatar
dengyihao 已提交
1616
  pCond->pSlotList = taosMemoryMalloc(sizeof(int32_t) * pCond->numOfCols);
H
Haojun Liao 已提交
1617
  if (pCond->colList == NULL || pCond->pSlotList == NULL) {
S
Shengliang Guan 已提交
1618
    terrno = TSDB_CODE_OUT_OF_MEMORY;
H
Haojun Liao 已提交
1619 1620
    taosMemoryFreeClear(pCond->colList);
    taosMemoryFreeClear(pCond->pSlotList);
1621 1622 1623 1624
    return terrno;
  }

  // TODO: get it from stable scan node
H
Haojun Liao 已提交
1625
  pCond->twindows = pTableScanNode->scanRange;
1626
  pCond->suid = pTableScanNode->scan.suid;
1627
  pCond->type = TIMEWINDOW_RANGE_CONTAINED;
H
Haojun Liao 已提交
1628
  pCond->startVersion = -1;
1629
  pCond->endVersion = -1;
1630 1631 1632 1633 1634 1635 1636 1637 1638 1639 1640 1641

  int32_t j = 0;
  for (int32_t i = 0; i < pCond->numOfCols; ++i) {
    STargetNode* pNode = (STargetNode*)nodesListGetNode(pTableScanNode->scan.pScanCols, i);
    SColumnNode* pColNode = (SColumnNode*)pNode->pExpr;
    if (pColNode->colType == COLUMN_TYPE_TAG) {
      continue;
    }

    pCond->colList[j].type = pColNode->node.resType.type;
    pCond->colList[j].bytes = pColNode->node.resType.bytes;
    pCond->colList[j].colId = pColNode->colId;
H
Haojun Liao 已提交
1642 1643

    pCond->pSlotList[j] = pNode->slotId;
1644 1645 1646 1647 1648 1649 1650
    j += 1;
  }

  pCond->numOfCols = j;
  return TSDB_CODE_SUCCESS;
}

H
Haojun Liao 已提交
1651 1652 1653 1654
void cleanupQueryTableDataCond(SQueryTableDataCond* pCond) {
  taosMemoryFreeClear(pCond->colList);
  taosMemoryFreeClear(pCond->pSlotList);
}
1655 1656 1657 1658 1659 1660 1661 1662 1663 1664 1665 1666 1667

int32_t convertFillType(int32_t mode) {
  int32_t type = TSDB_FILL_NONE;
  switch (mode) {
    case FILL_MODE_PREV:
      type = TSDB_FILL_PREV;
      break;
    case FILL_MODE_NONE:
      type = TSDB_FILL_NONE;
      break;
    case FILL_MODE_NULL:
      type = TSDB_FILL_NULL;
      break;
D
dapan1121 已提交
1668 1669 1670
    case FILL_MODE_NULL_F:
      type = TSDB_FILL_NULL_F;
      break;
1671 1672 1673 1674 1675 1676
    case FILL_MODE_NEXT:
      type = TSDB_FILL_NEXT;
      break;
    case FILL_MODE_VALUE:
      type = TSDB_FILL_SET_VALUE;
      break;
D
dapan1121 已提交
1677 1678 1679
    case FILL_MODE_VALUE_F:
      type = TSDB_FILL_SET_VALUE_F;
      break;
1680 1681 1682 1683 1684 1685 1686 1687 1688
    case FILL_MODE_LINEAR:
      type = TSDB_FILL_LINEAR;
      break;
    default:
      type = TSDB_FILL_NONE;
  }

  return type;
}
H
Haojun Liao 已提交
1689 1690 1691

static void getInitialStartTimeWindow(SInterval* pInterval, TSKEY ts, STimeWindow* w, bool ascQuery) {
  if (ascQuery) {
1692
    *w = getAlignQueryTimeWindow(pInterval, pInterval->precision, ts);
H
Haojun Liao 已提交
1693 1694
  } else {
    // the start position of the first time window in the endpoint that spreads beyond the queried last timestamp
1695
    *w = getAlignQueryTimeWindow(pInterval, pInterval->precision, ts);
H
Haojun Liao 已提交
1696 1697 1698 1699 1700 1701 1702 1703 1704 1705 1706 1707 1708 1709

    int64_t key = w->skey;
    while (key < ts) {  // moving towards end
      key = taosTimeAdd(key, pInterval->sliding, pInterval->slidingUnit, pInterval->precision);
      if (key >= ts) {
        break;
      }

      w->skey = key;
    }
  }
}

static STimeWindow doCalculateTimeWindow(int64_t ts, SInterval* pInterval) {
1710
  STimeWindow w = {0};
H
Haojun Liao 已提交
1711

1712 1713
  w.skey = taosTimeTruncate(ts, pInterval, pInterval->precision);
  w.ekey = taosTimeAdd(w.skey, pInterval->interval, pInterval->intervalUnit, pInterval->precision) - 1;
H
Haojun Liao 已提交
1714 1715 1716
  return w;
}

1717
STimeWindow getFirstQualifiedTimeWindow(int64_t ts, STimeWindow* pWindow, SInterval* pInterval, int32_t order) {
1718
  int32_t factor = (order == TSDB_ORDER_ASC) ? -1 : 1;
H
Haojun Liao 已提交
1719 1720 1721

  STimeWindow win = *pWindow;
  STimeWindow save = win;
1722
  while (win.skey <= ts && win.ekey >= ts) {
H
Haojun Liao 已提交
1723 1724 1725 1726 1727 1728 1729 1730 1731
    save = win;
    win.skey = taosTimeAdd(win.skey, factor * pInterval->sliding, pInterval->slidingUnit, pInterval->precision);
    win.ekey = taosTimeAdd(win.ekey, factor * pInterval->sliding, pInterval->slidingUnit, pInterval->precision);
  }

  return save;
}

// get the correct time window according to the handled timestamp
1732
// todo refactor
H
Haojun Liao 已提交
1733 1734 1735 1736 1737 1738 1739 1740 1741
STimeWindow getActiveTimeWindow(SDiskbasedBuf* pBuf, SResultRowInfo* pResultRowInfo, int64_t ts, SInterval* pInterval,
                                int32_t order) {
  STimeWindow w = {0};
  if (pResultRowInfo->cur.pageId == -1) {  // the first window, from the previous stored value
    getInitialStartTimeWindow(pInterval, ts, &w, (order == TSDB_ORDER_ASC));
    w.ekey = taosTimeAdd(w.skey, pInterval->interval, pInterval->intervalUnit, pInterval->precision) - 1;
    return w;
  }

1742 1743 1744 1745
  SResultRow* pRow = getResultRowByPos(pBuf, &pResultRowInfo->cur, false);
  if (pRow) {
    w = pRow->win;
  }
H
Haojun Liao 已提交
1746 1747 1748 1749 1750 1751 1752 1753 1754 1755 1756 1757
  // in case of typical time window, we can calculate time window directly.
  if (w.skey > ts || w.ekey < ts) {
    w = doCalculateTimeWindow(ts, pInterval);
  }

  if (pInterval->interval != pInterval->sliding) {
    // it is an sliding window query, in which sliding value is not equalled to
    // interval value, and we need to find the first qualified time window.
    w = getFirstQualifiedTimeWindow(ts, &w, pInterval, order);
  }

  return w;
1758 1759 1760 1761 1762 1763 1764
}

bool hasLimitOffsetInfo(SLimitInfo* pLimitInfo) {
  return (pLimitInfo->limit.limit != -1 || pLimitInfo->limit.offset != -1 || pLimitInfo->slimit.limit != -1 ||
          pLimitInfo->slimit.offset != -1);
}

1765 1766 1767 1768
bool hasSlimitOffsetInfo(SLimitInfo* pLimitInfo) {
  return (pLimitInfo->slimit.limit != -1 || pLimitInfo->slimit.offset != -1);
}

1769 1770 1771 1772 1773
void initLimitInfo(const SNode* pLimit, const SNode* pSLimit, SLimitInfo* pLimitInfo) {
  SLimit limit = {.limit = getLimit(pLimit), .offset = getOffset(pLimit)};
  SLimit slimit = {.limit = getLimit(pSLimit), .offset = getOffset(pSLimit)};

  pLimitInfo->limit = limit;
1774
  pLimitInfo->slimit = slimit;
1775 1776
  pLimitInfo->remainOffset = limit.offset;
  pLimitInfo->remainGroupOffset = slimit.offset;
1777
}
H
Haojun Liao 已提交
1778

1779 1780 1781 1782 1783
void resetLimitInfoForNextGroup(SLimitInfo* pLimitInfo) {
  pLimitInfo->numOfOutputRows = 0;
  pLimitInfo->remainOffset = pLimitInfo->limit.offset;
}

H
Haojun Liao 已提交
1784
uint64_t tableListGetSize(const STableListInfo* pTableList) {
1785
  ASSERT(taosArrayGetSize(pTableList->pTableList) == taosHashGetSize(pTableList->map));
H
Haojun Liao 已提交
1786 1787 1788
  return taosArrayGetSize(pTableList->pTableList);
}

dengyihao's avatar
dengyihao 已提交
1789
uint64_t tableListGetSuid(const STableListInfo* pTableList) { return pTableList->suid; }
H
Haojun Liao 已提交
1790 1791 1792 1793 1794 1795 1796 1797 1798

STableKeyInfo* tableListGetInfo(const STableListInfo* pTableList, int32_t index) {
  if (taosArrayGetSize(pTableList->pTableList) == 0) {
    return NULL;
  }

  return taosArrayGet(pTableList->pTableList, index);
}

H
Haojun Liao 已提交
1799 1800
uint64_t getTableGroupId(const STableListInfo* pTableList, uint64_t tableUid) {
  int32_t* slot = taosHashGet(pTableList->map, &tableUid, sizeof(tableUid));
1801
  ASSERT(pTableList->map != NULL && slot != NULL);
H
Haojun Liao 已提交
1802 1803

  STableKeyInfo* pKeyInfo = taosArrayGet(pTableList->pTableList, *slot);
1804
  ASSERT(pKeyInfo->uid == tableUid);
H
Haojun Liao 已提交
1805 1806 1807 1808

  return pKeyInfo->groupId;
}

H
Haojun Liao 已提交
1809
// TODO handle the group offset info, fix it, the rule of group output will be broken by this function
H
Haojun Liao 已提交
1810
int32_t tableListAddTableInfo(STableListInfo* pTableList, uint64_t uid, uint64_t gid) {
H
Haojun Liao 已提交
1811
  if (pTableList->map == NULL) {
1812
    ASSERT(taosArrayGetSize(pTableList->pTableList) == 0);
1813
    pTableList->map = taosHashInit(32, taosGetDefaultHashFunction(TSDB_DATA_TYPE_BINARY), false, HASH_ENTRY_LOCK);
H
Haojun Liao 已提交
1814 1815 1816 1817 1818 1819 1820 1821 1822 1823 1824 1825
  }

  STableKeyInfo keyInfo = {.uid = uid, .groupId = gid};
  taosArrayPush(pTableList->pTableList, &keyInfo);

  int32_t slot = (int32_t)taosArrayGetSize(pTableList->pTableList) - 1;
  taosHashPut(pTableList->map, &uid, sizeof(uid), &slot, sizeof(slot));

  qDebug("uid:%" PRIu64 ", groupId:%" PRIu64 " added into table list, slot:%d, total:%d", uid, gid, slot, slot + 1);
  return TSDB_CODE_SUCCESS;
}

H
Haojun Liao 已提交
1826
int32_t tableListGetGroupList(const STableListInfo* pTableList, int32_t ordinalGroupIndex, STableKeyInfo** pKeyInfo,
dengyihao's avatar
dengyihao 已提交
1827
                              int32_t* size) {
1828 1829 1830 1831
  int32_t totalGroups = tableListGetOutputGroups(pTableList);
  int32_t numOfTables =  tableListGetSize(pTableList);

  if (ordinalGroupIndex < 0 || ordinalGroupIndex >= totalGroups) {
H
Haojun Liao 已提交
1832 1833 1834 1835 1836
    return TSDB_CODE_INVALID_PARA;
  }

  // here handle two special cases:
  // 1. only one group exists, and 2. one table exists for each group.
1837 1838
  if (totalGroups == 1) {
    *size = numOfTables;
dengyihao's avatar
dengyihao 已提交
1839
    *pKeyInfo = (*size == 0) ? NULL : taosArrayGet(pTableList->pTableList, 0);
H
Haojun Liao 已提交
1840
    return TSDB_CODE_SUCCESS;
1841
  } else if (totalGroups == numOfTables) {
H
Haojun Liao 已提交
1842 1843 1844 1845 1846 1847
    *size = 1;
    *pKeyInfo = taosArrayGet(pTableList->pTableList, ordinalGroupIndex);
    return TSDB_CODE_SUCCESS;
  }

  int32_t offset = pTableList->groupOffset[ordinalGroupIndex];
1848
  if (ordinalGroupIndex < totalGroups - 1) {
1849
    *size = pTableList->groupOffset[ordinalGroupIndex + 1] - offset;
H
Haojun Liao 已提交
1850
  } else {
1851
    *size = numOfTables - offset;
H
Haojun Liao 已提交
1852 1853 1854 1855 1856 1857
  }

  *pKeyInfo = taosArrayGet(pTableList->pTableList, offset);
  return TSDB_CODE_SUCCESS;
}

H
Haojun Liao 已提交
1858
int32_t tableListGetOutputGroups(const STableListInfo* pTableList) { return pTableList->numOfOuputGroups; }
H
Haojun Liao 已提交
1859 1860 1861

bool oneTableForEachGroup(const STableListInfo* pTableList) { return pTableList->oneTableForEachGroup; }

H
Haojun Liao 已提交
1862 1863 1864 1865 1866 1867 1868 1869 1870 1871 1872 1873
STableListInfo* tableListCreate() {
  STableListInfo* pListInfo = taosMemoryCalloc(1, sizeof(STableListInfo));
  if (pListInfo == NULL) {
    terrno = TSDB_CODE_OUT_OF_MEMORY;
    return NULL;
  }

  pListInfo->pTableList = taosArrayInit(4, sizeof(STableKeyInfo));
  if (pListInfo->pTableList == NULL) {
    goto _error;
  }

1874
  pListInfo->map = taosHashInit(1024, taosGetDefaultHashFunction(TSDB_DATA_TYPE_BIGINT), false, HASH_ENTRY_LOCK);
H
Haojun Liao 已提交
1875 1876 1877 1878 1879 1880 1881 1882 1883 1884 1885 1886 1887 1888
  if (pListInfo->map == NULL) {
    goto _error;
  }

  pListInfo->numOfOuputGroups = 1;
  return pListInfo;

_error:
  tableListDestroy(pListInfo);
  terrno = TSDB_CODE_OUT_OF_MEMORY;
  return NULL;
}

void* tableListDestroy(STableListInfo* pTableListInfo) {
1889 1890 1891
  if (pTableListInfo == NULL) {
    return NULL;
  }
H
Haojun Liao 已提交
1892

H
Haojun Liao 已提交
1893 1894
  pTableListInfo->pTableList = taosArrayDestroy(pTableListInfo->pTableList);
  taosMemoryFreeClear(pTableListInfo->groupOffset);
H
Haojun Liao 已提交
1895

H
Haojun Liao 已提交
1896 1897 1898 1899 1900 1901 1902 1903 1904
  taosHashCleanup(pTableListInfo->map);

  pTableListInfo->pTableList = NULL;
  pTableListInfo->map = NULL;
  taosMemoryFree(pTableListInfo);
  return NULL;
}

void tableListClear(STableListInfo* pTableListInfo) {
H
Haojun Liao 已提交
1905 1906 1907 1908
  if (pTableListInfo == NULL) {
    return;
  }

H
Haojun Liao 已提交
1909 1910 1911 1912 1913 1914 1915 1916
  taosArrayClear(pTableListInfo->pTableList);
  taosHashClear(pTableListInfo->map);
  taosMemoryFree(pTableListInfo->groupOffset);
  pTableListInfo->numOfOuputGroups = 1;
  pTableListInfo->oneTableForEachGroup = false;
}

static int32_t orderbyGroupIdComparFn(const void* p1, const void* p2) {
dengyihao's avatar
dengyihao 已提交
1917 1918
  STableKeyInfo* pInfo1 = (STableKeyInfo*)p1;
  STableKeyInfo* pInfo2 = (STableKeyInfo*)p2;
H
Haojun Liao 已提交
1919 1920 1921 1922

  if (pInfo1->groupId == pInfo2->groupId) {
    return 0;
  } else {
dengyihao's avatar
dengyihao 已提交
1923
    return pInfo1->groupId < pInfo2->groupId ? -1 : 1;
H
Haojun Liao 已提交
1924 1925 1926 1927 1928 1929 1930 1931 1932 1933
  }
}

static int32_t sortTableGroup(STableListInfo* pTableListInfo) {
  taosArraySort(pTableListInfo->pTableList, orderbyGroupIdComparFn);
  int32_t size = taosArrayGetSize(pTableListInfo->pTableList);

  SArray* pList = taosArrayInit(4, sizeof(int32_t));

  STableKeyInfo* pInfo = taosArrayGet(pTableListInfo->pTableList, 0);
dengyihao's avatar
dengyihao 已提交
1934
  uint64_t       gid = pInfo->groupId;
1935

H
Haojun Liao 已提交
1936 1937
  int32_t start = 0;
  taosArrayPush(pList, &start);
1938

dengyihao's avatar
dengyihao 已提交
1939
  for (int32_t i = 1; i < size; ++i) {
H
Haojun Liao 已提交
1940 1941 1942 1943 1944 1945 1946 1947 1948
    pInfo = taosArrayGet(pTableListInfo->pTableList, i);
    if (pInfo->groupId != gid) {
      taosArrayPush(pList, &i);
      gid = pInfo->groupId;
    }
  }

  pTableListInfo->numOfOuputGroups = taosArrayGetSize(pList);
  pTableListInfo->groupOffset = taosMemoryMalloc(sizeof(int32_t) * pTableListInfo->numOfOuputGroups);
H
Haojun Liao 已提交
1949 1950 1951 1952 1953
  if (pTableListInfo->groupOffset == NULL) {
    taosArrayDestroy(pList);
    return TSDB_CODE_OUT_OF_MEMORY;
  }

H
Haojun Liao 已提交
1954 1955 1956 1957 1958
  memcpy(pTableListInfo->groupOffset, taosArrayGet(pList, 0), sizeof(int32_t) * pTableListInfo->numOfOuputGroups);
  taosArrayDestroy(pList);
  return TDB_CODE_SUCCESS;
}

dengyihao's avatar
dengyihao 已提交
1959 1960
int32_t buildGroupIdMapForAllTables(STableListInfo* pTableListInfo, SReadHandle* pHandle, SNodeList* group,
                                    bool groupSort) {
H
Haojun Liao 已提交
1961
  int32_t code = TSDB_CODE_SUCCESS;
1962
  ASSERT(pTableListInfo->map != NULL);
H
Haojun Liao 已提交
1963

dengyihao's avatar
dengyihao 已提交
1964
  bool   groupByTbname = groupbyTbname(group);
H
Haojun Liao 已提交
1965 1966 1967 1968
  size_t numOfTables = taosArrayGetSize(pTableListInfo->pTableList);
  if (group == NULL || groupByTbname) {
    for (int32_t i = 0; i < numOfTables; i++) {
      STableKeyInfo* info = taosArrayGet(pTableListInfo->pTableList, i);
dengyihao's avatar
dengyihao 已提交
1969
      info->groupId = groupByTbname ? info->uid : 0;
H
Haojun Liao 已提交
1970 1971 1972 1973 1974 1975 1976 1977 1978 1979 1980 1981 1982 1983 1984 1985 1986 1987 1988 1989 1990 1991 1992
    }

    pTableListInfo->oneTableForEachGroup = groupByTbname;

    if (groupSort && groupByTbname) {
      taosArraySort(pTableListInfo->pTableList, orderbyGroupIdComparFn);
      pTableListInfo->numOfOuputGroups = numOfTables;
    } else {
      pTableListInfo->numOfOuputGroups = 1;
    }
  } else {
    code = getColInfoResultForGroupby(pHandle->meta, group, pTableListInfo);
    if (code != TSDB_CODE_SUCCESS) {
      return code;
    }

    if (groupSort) {
      code = sortTableGroup(pTableListInfo);
    }
  }

  // add all table entry in the hash map
  size_t size = taosArrayGetSize(pTableListInfo->pTableList);
dengyihao's avatar
dengyihao 已提交
1993
  for (int32_t i = 0; i < size; ++i) {
H
Haojun Liao 已提交
1994 1995 1996 1997 1998 1999 2000 2001 2002
    STableKeyInfo* p = taosArrayGet(pTableListInfo->pTableList, i);
    taosHashPut(pTableListInfo->map, &p->uid, sizeof(uint64_t), &i, sizeof(int32_t));
  }

  return code;
}

int32_t createScanTableListInfo(SScanPhysiNode* pScanNode, SNodeList* pGroupTags, bool groupSort, SReadHandle* pHandle,
                                STableListInfo* pTableListInfo, SNode* pTagCond, SNode* pTagIndexCond,
H
Haojun Liao 已提交
2003
                                SExecTaskInfo* pTaskInfo) {
dengyihao's avatar
dengyihao 已提交
2004
  int64_t     st = taosGetTimestampUs();
H
Haojun Liao 已提交
2005
  const char* idStr = GET_TASKID(pTaskInfo);
H
Haojun Liao 已提交
2006 2007 2008 2009 2010 2011

  if (pHandle == NULL) {
    qError("invalid handle, in creating operator tree, %s", idStr);
    return TSDB_CODE_INVALID_PARA;
  }

2012
  int32_t code = getTableList(pHandle->meta, pHandle->vnode, pScanNode, pTagCond, pTagIndexCond, pTableListInfo, idStr);
H
Haojun Liao 已提交
2013 2014 2015 2016 2017
  if (code != TSDB_CODE_SUCCESS) {
    qError("failed to getTableList, code: %s", tstrerror(code));
    return code;
  }

H
Haojun Liao 已提交
2018
  int32_t numOfTables = taosArrayGetSize(pTableListInfo->pTableList);
2019
  ASSERT(pTableListInfo->numOfOuputGroups == 1);
H
Haojun Liao 已提交
2020 2021

  int64_t st1 = taosGetTimestampUs();
H
Haojun Liao 已提交
2022
  pTaskInfo->cost.extractListTime = (st1 - st) / 1000.0;
H
Haojun Liao 已提交
2023 2024
  qDebug("extract queried table list completed, %d tables, elapsed time:%.2f ms %s", numOfTables,
         pTaskInfo->cost.extractListTime, idStr);
H
Haojun Liao 已提交
2025

H
Haojun Liao 已提交
2026
  if (numOfTables == 0) {
H
Haojun Liao 已提交
2027 2028 2029 2030
    qDebug("no table qualified for query, %s" PRIx64, idStr);
    return TSDB_CODE_SUCCESS;
  }

2031
  code = buildGroupIdMapForAllTables(pTableListInfo, pHandle, pGroupTags, groupSort);
H
Haojun Liao 已提交
2032 2033 2034 2035
  if (code != TSDB_CODE_SUCCESS) {
    return code;
  }

dengyihao's avatar
dengyihao 已提交
2036
  pTaskInfo->cost.groupIdMapTime = (taosGetTimestampUs() - st1) / 1000.0;
H
Haojun Liao 已提交
2037
  qDebug("generate group id map completed, elapsed time:%.2f ms %s", pTaskInfo->cost.groupIdMapTime, idStr);
H
Haojun Liao 已提交
2038 2039

  return TSDB_CODE_SUCCESS;
H
Haojun Liao 已提交
2040
}
H
Haojun Liao 已提交
2041 2042 2043 2044 2045 2046 2047 2048 2049

void printDataBlock(SSDataBlock* pBlock, const char* flag) {
  if (!pBlock || pBlock->info.rows == 0) {
    qDebug("===stream===printDataBlock: Block is Null or Empty");
    return;
  }
  char* pBuf = NULL;
  qDebug("%s", dumpBlockData(pBlock, flag, &pBuf));
  taosMemoryFree(pBuf);
dengyihao's avatar
dengyihao 已提交
2050
}