parCalcConst.c 12.4 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
static int32_t calcConstQuery(SCalcConstContext* pCxt, SNode* pStmt, bool subquery) {
  int32_t code = TSDB_CODE_SUCCESS;
X
Xiaoyu Wang 已提交
325 326
  switch (nodeType(pStmt)) {
    case QUERY_NODE_SELECT_STMT:
327 328
      code = calcConstSelect(pCxt, (SSelectStmt*)pStmt, subquery);
      break;
D
dapan1121 已提交
329
    case QUERY_NODE_EXPLAIN_STMT:
330 331 332 333
      code = calcConstQuery(pCxt, ((SExplainStmt*)pStmt)->pQuery, subquery);
      break;
    case QUERY_NODE_SET_OPERATOR: {
      SSetOperator* pSetOp = (SSetOperator*)pStmt;
334
      code = calcConstQuery(pCxt, pSetOp->pLeft, false);
335
      if (TSDB_CODE_SUCCESS == code) {
336
        code = calcConstQuery(pCxt, pSetOp->pRight, false);
337 338 339
      }
      break;
    }
X
Xiaoyu Wang 已提交
340 341 342
    case QUERY_NODE_DELETE_STMT:
      code = calcConstDelete(pCxt, (SDeleteStmt*)pStmt);
      break;
343 344 345
    case QUERY_NODE_INSERT_STMT:
      code = calcConstInsert(pCxt, (SInsertStmt*)pStmt);
      break;
X
Xiaoyu Wang 已提交
346 347 348
    default:
      break;
  }
349
  return code;
X
Xiaoyu Wang 已提交
350 351
}

X
Xiaoyu Wang 已提交
352
static bool isEmptyResultQuery(SNode* pStmt) {
353
  bool isEmptyResult = false;
X
Xiaoyu Wang 已提交
354 355
  switch (nodeType(pStmt)) {
    case QUERY_NODE_SELECT_STMT:
356 357
      isEmptyResult = ((SSelectStmt*)pStmt)->isEmptyResult;
      break;
X
Xiaoyu Wang 已提交
358
    case QUERY_NODE_EXPLAIN_STMT:
359 360 361 362 363 364 365 366 367 368
      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 已提交
369 370 371
    default:
      break;
  }
372
  return isEmptyResult;
X
Xiaoyu Wang 已提交
373 374
}

X
Xiaoyu Wang 已提交
375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399
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 已提交
400
int32_t calculateConstant(SParseContext* pParseCxt, SQuery* pQuery) {
X
Xiaoyu Wang 已提交
401 402 403 404 405
  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 已提交
406 407 408 409 410
  if (TSDB_CODE_SUCCESS == code) {
    resetProjectNullType(pQuery->pRoot);
    if (isEmptyResultQuery(pQuery->pRoot)) {
      pQuery->execMode = QUERY_EXEC_MODE_EMPTY_RESULT;
    }
X
Xiaoyu Wang 已提交
411 412
  }
  return code;
X
Xiaoyu Wang 已提交
413
}