parCalcConst.c 13.9 KB
Newer Older
X
Xiaoyu Wang 已提交
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/>.
 */

X
Xiaoyu Wang 已提交
16
#include "functionMgt.h"
X
Xiaoyu Wang 已提交
17 18
#include "parInt.h"
#include "scalar.h"
X
Xiaoyu Wang 已提交
19
#include "ttime.h"
X
Xiaoyu Wang 已提交
20 21

typedef struct SCalcConstContext {
X
Xiaoyu Wang 已提交
22
  SParseContext* pParseCxt;
X
Xiaoyu Wang 已提交
23 24
  SMsgBuf        msgBuf;
  int32_t        code;
X
Xiaoyu Wang 已提交
25 26
} SCalcConstContext;

27
static int32_t calcConstQuery(SCalcConstContext* pCxt, SNode* pStmt, bool subquery);
X
Xiaoyu Wang 已提交
28

29 30
static int32_t calcConstSubquery(SCalcConstContext* pCxt, STempTableNode* pTempTable) {
  return calcConstQuery(pCxt, pTempTable->pSubquery, true);
X
Xiaoyu Wang 已提交
31 32
}

33 34 35
static int32_t calcConstNode(SNode** pNode) {
  if (NULL == *pNode) {
    return TSDB_CODE_SUCCESS;
X
Xiaoyu Wang 已提交
36 37
  }

X
Xiaoyu Wang 已提交
38
  SNode*  pNew = NULL;
39 40 41
  int32_t code = scalarCalculateConstants(*pNode, &pNew);
  if (TSDB_CODE_SUCCESS == code) {
    *pNode = pNew;
X
Xiaoyu Wang 已提交
42
  }
43
  return code;
X
Xiaoyu Wang 已提交
44 45
}

46 47 48
static int32_t calcConstList(SNodeList* pList) {
  SNode* pNode = NULL;
  FOREACH(pNode, pList) {
X
Xiaoyu Wang 已提交
49
    SNode*  pNew = NULL;
50 51 52 53 54
    int32_t code = scalarCalculateConstants(pNode, &pNew);
    if (TSDB_CODE_SUCCESS == code) {
      REPLACE_NODE(pNew);
    } else {
      return code;
X
Xiaoyu Wang 已提交
55 56
    }
  }
57
  return TSDB_CODE_SUCCESS;
X
Xiaoyu Wang 已提交
58 59
}

60 61 62 63 64 65 66 67
static bool isCondition(const SNode* pNode) {
  if (QUERY_NODE_OPERATOR == nodeType(pNode)) {
    return nodesIsComparisonOp((const SOperatorNode*)pNode);
  }
  return (QUERY_NODE_LOGIC_CONDITION == nodeType(pNode));
}

static int32_t rewriteIsTrue(SNode* pSrc, SNode** pIsTrue) {
68
  SOperatorNode* pOp = (SOperatorNode*)nodesMakeNode(QUERY_NODE_OPERATOR);
69 70 71 72 73
  if (NULL == pOp) {
    return TSDB_CODE_OUT_OF_MEMORY;
  }
  pOp->opType = OP_TYPE_IS_TRUE;
  pOp->pLeft = pSrc;
D
dapan1121 已提交
74 75
  pOp->node.resType.type = TSDB_DATA_TYPE_BOOL;
  pOp->node.resType.bytes = tDataTypes[TSDB_DATA_TYPE_BOOL].bytes;
76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104
  *pIsTrue = (SNode*)pOp;
  return TSDB_CODE_SUCCESS;
}

static EDealRes doRewriteCondition(SNode** pNode, void* pContext) {
  if (QUERY_NODE_LOGIC_CONDITION == nodeType(*pNode)) {
    SNode* pParam = NULL;
    FOREACH(pParam, ((SLogicConditionNode*)*pNode)->pParameterList) {
      if (!isCondition(pParam)) {
        SNode* pIsTrue = NULL;
        if (TSDB_CODE_SUCCESS != rewriteIsTrue(pParam, &pIsTrue)) {
          ((SCalcConstContext*)pContext)->code = TSDB_CODE_OUT_OF_MEMORY;
          return DEAL_RES_ERROR;
        }
        REPLACE_NODE(pIsTrue);
      }
    }
  }
  return DEAL_RES_CONTINUE;
}

static int32_t rewriteCondition(SCalcConstContext* pCxt, SNode** pNode) {
  if (!isCondition(*pNode)) {
    return rewriteIsTrue(*pNode, pNode);
  }
  nodesRewriteExprPostOrder(pNode, doRewriteCondition, pCxt);
  return pCxt->code;
}

105 106 107 108 109 110 111 112
static int32_t calcConstCondition(SCalcConstContext* pCxt, SNode** pNode) {
  int32_t code = rewriteCondition(pCxt, pNode);
  if (TSDB_CODE_SUCCESS == code) {
    code = calcConstNode(pNode);
  }
  return code;
}

113
static int32_t rewriteConditionForFromTable(SCalcConstContext* pCxt, SNode* pTable) {
114 115 116 117 118
  int32_t code = TSDB_CODE_SUCCESS;
  switch (nodeType(pTable)) {
    case QUERY_NODE_TEMP_TABLE: {
      code = calcConstSubquery(pCxt, (STempTableNode*)pTable);
      break;
119
    }
120 121 122 123 124 125 126 127 128 129 130
    case QUERY_NODE_JOIN_TABLE: {
      SJoinTableNode* pJoin = (SJoinTableNode*)pTable;
      code = rewriteConditionForFromTable(pCxt, pJoin->pLeft);
      if (TSDB_CODE_SUCCESS == code) {
        code = rewriteConditionForFromTable(pCxt, pJoin->pRight);
      }
      if (TSDB_CODE_SUCCESS == code && NULL != pJoin->pOnCond) {
        code = calcConstCondition(pCxt, &pJoin->pOnCond);
      }
      // todo empty table
      break;
X
Xiaoyu Wang 已提交
131
    }
132 133
    default:
      break;
134
  }
135 136 137
  return code;
}

X
Xiaoyu Wang 已提交
138 139
static int32_t calcConstFromTable(SCalcConstContext* pCxt, SNode* pTable) {
  return rewriteConditionForFromTable(pCxt, pTable);
140 141
}

X
Xiaoyu Wang 已提交
142
static void rewriteConstCondition(SNode** pCond, bool* pAlwaysFalse) {
X
Xiaoyu Wang 已提交
143 144 145 146 147 148 149
  if (QUERY_NODE_VALUE != nodeType(*pCond)) {
    return;
  }
  if (((SValueNode*)*pCond)->datum.b) {
    nodesDestroyNode(*pCond);
    *pCond = NULL;
  } else {
X
Xiaoyu Wang 已提交
150
    *pAlwaysFalse = true;
X
Xiaoyu Wang 已提交
151 152 153
  }
}

X
Xiaoyu Wang 已提交
154
static int32_t calcConstStmtCondition(SCalcConstContext* pCxt, SNode** pCond, bool* pAlwaysFalse) {
155 156 157 158
  if (NULL == *pCond) {
    return TSDB_CODE_SUCCESS;
  }

159 160 161
  int32_t code = rewriteCondition(pCxt, pCond);
  if (TSDB_CODE_SUCCESS == code) {
    code = calcConstNode(pCond);
X
Xiaoyu Wang 已提交
162
  }
163
  if (TSDB_CODE_SUCCESS == code) {
X
Xiaoyu Wang 已提交
164
    rewriteConstCondition(pCond, pAlwaysFalse);
165
  }
166
  return code;
167 168
}

D
dapan1121 已提交
169
static int32_t calcConstProject(SNode* pProject, bool dual, SNode** pNew) {
170 171
  SArray* pAssociation = NULL;
  if (NULL != ((SExprNode*)pProject)->pAssociation) {
H
Haojun Liao 已提交
172
    pAssociation = taosArrayDup(((SExprNode*)pProject)->pAssociation, NULL);
173 174 175
    if (NULL == pAssociation) {
      return TSDB_CODE_OUT_OF_MEMORY;
    }
X
Xiaoyu Wang 已提交
176
  }
177

178 179
  char aliasName[TSDB_COL_NAME_LEN] = {0};
  strcpy(aliasName, ((SExprNode*)pProject)->aliasName);
D
dapan1121 已提交
180 181 182 183 184 185
  int32_t code = TSDB_CODE_SUCCESS;
  if (dual) {
    code = scalarCalculateConstantsFromDual(pProject, pNew);
  } else {
    code = scalarCalculateConstants(pProject, pNew);
  }
X
Xiaoyu Wang 已提交
186
  if (TSDB_CODE_SUCCESS == code && QUERY_NODE_VALUE == nodeType(*pNew) && NULL != pAssociation) {
187
    strcpy(((SExprNode*)*pNew)->aliasName, aliasName);
188 189
    int32_t size = taosArrayGetSize(pAssociation);
    for (int32_t i = 0; i < size; ++i) {
X
Xiaoyu Wang 已提交
190
      SNode** pCol = taosArrayGetP(pAssociation, i);
X
Xiaoyu Wang 已提交
191
      nodesDestroyNode(*pCol);
X
Xiaoyu Wang 已提交
192
      *pCol = nodesCloneNode(*pNew);
193
      if (NULL == *pCol) {
X
Xiaoyu Wang 已提交
194 195
        code = TSDB_CODE_OUT_OF_MEMORY;
        break;
196 197
      }
    }
X
Xiaoyu Wang 已提交
198
  }
X
Xiaoyu Wang 已提交
199
  taosArrayDestroy(pAssociation);
200 201 202
  return code;
}

203
static bool isUselessCol(SExprNode* pProj) {
204 205
  if (QUERY_NODE_FUNCTION == nodeType(pProj) && !fmIsScalarFunc(((SFunctionNode*)pProj)->funcId) &&
      !fmIsPseudoColumnFunc(((SFunctionNode*)pProj)->funcId)) {
206 207 208 209 210
    return false;
  }
  return NULL == ((SExprNode*)pProj)->pAssociation;
}

211 212 213 214 215 216 217 218 219 220 221 222 223
static SNode* createConstantValue() {
  SValueNode* pVal = (SValueNode*)nodesMakeNode(QUERY_NODE_VALUE);
  if (NULL == pVal) {
    return NULL;
  }
  pVal->node.resType.type = TSDB_DATA_TYPE_INT;
  pVal->node.resType.bytes = tDataTypes[TSDB_DATA_TYPE_INT].bytes;
  const int32_t val = 1;
  nodesSetValueNodeValue(pVal, (void*)&val);
  pVal->translate = true;
  return (SNode*)pVal;
}

224
static int32_t calcConstProjections(SCalcConstContext* pCxt, SSelectStmt* pSelect, bool subquery) {
225
  SNode* pProj = NULL;
226
  WHERE_EACH(pProj, pSelect->pProjectionList) {
227
    if (subquery && !pSelect->isDistinct && isUselessCol((SExprNode*)pProj)) {
228
      ERASE_NODE(pSelect->pProjectionList);
229 230
      continue;
    }
X
Xiaoyu Wang 已提交
231
    SNode*  pNew = NULL;
D
dapan1121 已提交
232
    int32_t code = calcConstProject(pProj, (NULL == pSelect->pFromTable), &pNew);
233 234 235 236 237 238
    if (TSDB_CODE_SUCCESS == code) {
      REPLACE_NODE(pNew);
    } else {
      return code;
    }
    WHERE_NEXT;
X
Xiaoyu Wang 已提交
239
  }
240 241 242
  if (0 == LIST_LENGTH(pSelect->pProjectionList)) {
    return nodesListStrictAppend(pSelect->pProjectionList, createConstantValue());
  }
243 244 245
  return TSDB_CODE_SUCCESS;
}

246 247 248 249 250 251 252 253 254 255 256 257
static int32_t calcConstGroupBy(SCalcConstContext* pCxt, SSelectStmt* pSelect) {
  int32_t code = calcConstList(pSelect->pGroupByList);
  if (TSDB_CODE_SUCCESS == code) {
    SNode* pNode = NULL;
    FOREACH(pNode, pSelect->pGroupByList) {
      SNode* pGroupPara = NULL;
      FOREACH(pGroupPara, ((SGroupingSetNode*)pNode)->pParameterList) {
        if (QUERY_NODE_VALUE != nodeType(pGroupPara)) {
          return code;
        }
      }
    }
X
Xiaoyu Wang 已提交
258
    NODES_DESTORY_LIST(pSelect->pGroupByList);
259 260 261 262
  }
  return code;
}

263 264 265 266 267
static int32_t calcConstSelectWithoutFrom(SCalcConstContext* pCxt, SSelectStmt* pSelect, bool subquery) {
  return calcConstProjections(pCxt, pSelect, subquery);
}

static int32_t calcConstSelectFrom(SCalcConstContext* pCxt, SSelectStmt* pSelect, bool subquery) {
X
Xiaoyu Wang 已提交
268
  int32_t code = calcConstFromTable(pCxt, pSelect->pFromTable);
269
  if (TSDB_CODE_SUCCESS == code) {
X
Xiaoyu Wang 已提交
270
    code = calcConstProjections(pCxt, pSelect, subquery);
X
Xiaoyu Wang 已提交
271
  }
272
  if (TSDB_CODE_SUCCESS == code) {
X
Xiaoyu Wang 已提交
273
    code = calcConstStmtCondition(pCxt, &pSelect->pWhere, &pSelect->isEmptyResult);
X
Xiaoyu Wang 已提交
274
  }
275 276
  if (TSDB_CODE_SUCCESS == code) {
    code = calcConstList(pSelect->pPartitionByList);
X
Xiaoyu Wang 已提交
277
  }
278 279 280 281 282 283
  if (TSDB_CODE_SUCCESS == code) {
    code = calcConstList(pSelect->pTags);
  }
  if (TSDB_CODE_SUCCESS == code) {
    code = calcConstNode(&pSelect->pSubtable);
  }
284 285
  if (TSDB_CODE_SUCCESS == code) {
    code = calcConstNode(&pSelect->pWindow);
X
Xiaoyu Wang 已提交
286
  }
287
  if (TSDB_CODE_SUCCESS == code) {
288
    code = calcConstGroupBy(pCxt, pSelect);
289 290
  }
  if (TSDB_CODE_SUCCESS == code) {
X
Xiaoyu Wang 已提交
291
    code = calcConstStmtCondition(pCxt, &pSelect->pHaving, &pSelect->isEmptyResult);
292 293 294 295 296
  }
  if (TSDB_CODE_SUCCESS == code) {
    code = calcConstList(pSelect->pOrderByList);
  }
  return code;
X
Xiaoyu Wang 已提交
297 298
}

299 300 301 302 303 304 305 306
static int32_t calcConstSelect(SCalcConstContext* pCxt, SSelectStmt* pSelect, bool subquery) {
  if (NULL == pSelect->pFromTable) {
    return calcConstSelectWithoutFrom(pCxt, pSelect, subquery);
  } else {
    return calcConstSelectFrom(pCxt, pSelect, subquery);
  }
}

X
Xiaoyu Wang 已提交
307 308 309 310 311 312 313 314
static int32_t calcConstDelete(SCalcConstContext* pCxt, SDeleteStmt* pDelete) {
  int32_t code = calcConstFromTable(pCxt, pDelete->pFromTable);
  if (TSDB_CODE_SUCCESS == code) {
    code = calcConstStmtCondition(pCxt, &pDelete->pWhere, &pDelete->deleteZeroRows);
  }
  return code;
}

315 316 317 318 319 320 321 322
static int32_t calcConstInsert(SCalcConstContext* pCxt, SInsertStmt* pInsert) {
  int32_t code = calcConstFromTable(pCxt, pInsert->pTable);
  if (TSDB_CODE_SUCCESS == code) {
    code = calcConstQuery(pCxt, pInsert->pQuery, false);
  }
  return code;
}

323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373
static SNodeList* getChildProjection(SNode* pStmt) {
  switch (nodeType(pStmt)) {
    case QUERY_NODE_SELECT_STMT:
      return ((SSelectStmt*)pStmt)->pProjectionList;
    case QUERY_NODE_SET_OPERATOR:
      return ((SSetOperator*)pStmt)->pProjectionList;
    default:
      break;
  }
  return NULL;
}

static void eraseSetOpChildProjection(SSetOperator* pSetOp, int32_t index) {
  SNodeList* pLeftProjs = getChildProjection(pSetOp->pLeft);
  nodesListErase(pLeftProjs, nodesListGetCell(pLeftProjs, index));
  SNodeList* pRightProjs = getChildProjection(pSetOp->pRight);
  nodesListErase(pRightProjs, nodesListGetCell(pRightProjs, index));
}

static int32_t calcConstSetOpProjections(SCalcConstContext* pCxt, SSetOperator* pSetOp, bool subquery) {
  int32_t index = 0;
  SNode*  pProj = NULL;
  WHERE_EACH(pProj, pSetOp->pProjectionList) {
    if (subquery && isUselessCol((SExprNode*)pProj)) {
      ERASE_NODE(pSetOp->pProjectionList);
      eraseSetOpChildProjection(pSetOp, index);
      continue;
    }
    ++index;
    WHERE_NEXT;
  }
  if (0 == LIST_LENGTH(pSetOp->pProjectionList)) {
    return nodesListStrictAppend(pSetOp->pProjectionList, createConstantValue());
  }
  return TSDB_CODE_SUCCESS;
}

static int32_t calcConstSetOperator(SCalcConstContext* pCxt, SSetOperator* pSetOp, bool subquery) {
  int32_t code = calcConstSetOpProjections(pCxt, pSetOp, subquery);
  if (TSDB_CODE_SUCCESS == code) {
    code = calcConstQuery(pCxt, pSetOp->pLeft, false);
  }
  if (TSDB_CODE_SUCCESS == code) {
    code = calcConstQuery(pCxt, pSetOp->pRight, false);
  }
  if (TSDB_CODE_SUCCESS == code) {
    code = calcConstList(pSetOp->pOrderByList);
  }
  return code;
}

374 375
static int32_t calcConstQuery(SCalcConstContext* pCxt, SNode* pStmt, bool subquery) {
  int32_t code = TSDB_CODE_SUCCESS;
X
Xiaoyu Wang 已提交
376 377
  switch (nodeType(pStmt)) {
    case QUERY_NODE_SELECT_STMT:
378 379
      code = calcConstSelect(pCxt, (SSelectStmt*)pStmt, subquery);
      break;
D
dapan1121 已提交
380
    case QUERY_NODE_EXPLAIN_STMT:
381 382 383
      code = calcConstQuery(pCxt, ((SExplainStmt*)pStmt)->pQuery, subquery);
      break;
    case QUERY_NODE_SET_OPERATOR: {
384
      code = calcConstSetOperator(pCxt, (SSetOperator*)pStmt, subquery);
385 386
      break;
    }
X
Xiaoyu Wang 已提交
387 388 389
    case QUERY_NODE_DELETE_STMT:
      code = calcConstDelete(pCxt, (SDeleteStmt*)pStmt);
      break;
390 391 392
    case QUERY_NODE_INSERT_STMT:
      code = calcConstInsert(pCxt, (SInsertStmt*)pStmt);
      break;
X
Xiaoyu Wang 已提交
393 394 395
    default:
      break;
  }
396
  return code;
X
Xiaoyu Wang 已提交
397 398
}

X
Xiaoyu Wang 已提交
399
static bool isEmptyResultQuery(SNode* pStmt) {
400
  bool isEmptyResult = false;
X
Xiaoyu Wang 已提交
401 402
  switch (nodeType(pStmt)) {
    case QUERY_NODE_SELECT_STMT:
403 404
      isEmptyResult = ((SSelectStmt*)pStmt)->isEmptyResult;
      break;
X
Xiaoyu Wang 已提交
405
    case QUERY_NODE_EXPLAIN_STMT:
406 407 408 409 410 411 412 413 414 415
      isEmptyResult = isEmptyResultQuery(((SExplainStmt*)pStmt)->pQuery);
      break;
    case QUERY_NODE_SET_OPERATOR: {
      SSetOperator* pSetOp = (SSetOperator*)pStmt;
      isEmptyResult = isEmptyResultQuery(pSetOp->pLeft);
      if (isEmptyResult) {
        isEmptyResult = isEmptyResultQuery(pSetOp->pRight);
      }
      break;
    }
X
Xiaoyu Wang 已提交
416 417 418
    default:
      break;
  }
419
  return isEmptyResult;
X
Xiaoyu Wang 已提交
420 421
}

X
Xiaoyu Wang 已提交
422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446
static void resetProjectNullTypeImpl(SNodeList* pProjects) {
  SNode* pProj = NULL;
  FOREACH(pProj, pProjects) {
    SExprNode* pExpr = (SExprNode*)pProj;
    if (TSDB_DATA_TYPE_NULL == pExpr->resType.type) {
      pExpr->resType.type = TSDB_DATA_TYPE_VARCHAR;
      pExpr->resType.bytes = 0;
    }
  }
}

static void resetProjectNullType(SNode* pStmt) {
  switch (nodeType(pStmt)) {
    case QUERY_NODE_SELECT_STMT:
      resetProjectNullTypeImpl(((SSelectStmt*)pStmt)->pProjectionList);
      break;
    case QUERY_NODE_SET_OPERATOR: {
      resetProjectNullTypeImpl(((SSetOperator*)pStmt)->pProjectionList);
      break;
    }
    default:
      break;
  }
}

X
Xiaoyu Wang 已提交
447
int32_t calculateConstant(SParseContext* pParseCxt, SQuery* pQuery) {
X
Xiaoyu Wang 已提交
448 449 450 451 452
  SCalcConstContext cxt = {.pParseCxt = pParseCxt,
                           .msgBuf.buf = pParseCxt->pMsg,
                           .msgBuf.len = pParseCxt->msgLen,
                           .code = TSDB_CODE_SUCCESS};
  int32_t           code = calcConstQuery(&cxt, pQuery->pRoot, false);
X
Xiaoyu Wang 已提交
453 454 455 456 457
  if (TSDB_CODE_SUCCESS == code) {
    resetProjectNullType(pQuery->pRoot);
    if (isEmptyResultQuery(pQuery->pRoot)) {
      pQuery->execMode = QUERY_EXEC_MODE_EMPTY_RESULT;
    }
X
Xiaoyu Wang 已提交
458 459
  }
  return code;
X
Xiaoyu Wang 已提交
460
}