parCalcConst.c 11.0 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
}

169 170 171
static int32_t calcConstProject(SNode* pProject, SNode** pNew) {
  SArray* pAssociation = NULL;
  if (NULL != ((SExprNode*)pProject)->pAssociation) {
X
fix  
Xiaoyu Wang 已提交
172
    pAssociation = taosArrayDup(((SExprNode*)pProject)->pAssociation);
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);
180
  int32_t code = scalarCalculateConstants(pProject, pNew);
X
Xiaoyu Wang 已提交
181
  if (TSDB_CODE_SUCCESS == code && QUERY_NODE_VALUE == nodeType(*pNew) && NULL != pAssociation) {
182
    strcpy(((SExprNode*)*pNew)->aliasName, aliasName);
183 184
    int32_t size = taosArrayGetSize(pAssociation);
    for (int32_t i = 0; i < size; ++i) {
X
Xiaoyu Wang 已提交
185
      SNode** pCol = taosArrayGetP(pAssociation, i);
X
Xiaoyu Wang 已提交
186
      nodesDestroyNode(*pCol);
X
Xiaoyu Wang 已提交
187
      *pCol = nodesCloneNode(*pNew);
188
      if (NULL == *pCol) {
X
Xiaoyu Wang 已提交
189 190
        code = TSDB_CODE_OUT_OF_MEMORY;
        break;
191 192
      }
    }
X
Xiaoyu Wang 已提交
193
  }
X
Xiaoyu Wang 已提交
194
  taosArrayDestroy(pAssociation);
195 196 197
  return code;
}

198 199 200 201 202 203 204
static bool isUselessCol(bool hasSelectValFunc, SExprNode* pProj) {
  if (hasSelectValFunc && QUERY_NODE_FUNCTION == nodeType(pProj) && fmIsSelectFunc(((SFunctionNode*)pProj)->funcId)) {
    return false;
  }
  return NULL == ((SExprNode*)pProj)->pAssociation;
}

205 206 207 208 209 210 211 212 213 214 215 216 217
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;
}

218
static int32_t calcConstProjections(SCalcConstContext* pCxt, SSelectStmt* pSelect, bool subquery) {
219
  SNode* pProj = NULL;
220 221 222
  WHERE_EACH(pProj, pSelect->pProjectionList) {
    if (subquery && isUselessCol(pSelect->hasSelectValFunc, (SExprNode*)pProj)) {
      ERASE_NODE(pSelect->pProjectionList);
223 224
      continue;
    }
X
Xiaoyu Wang 已提交
225
    SNode*  pNew = NULL;
226 227 228 229 230 231 232
    int32_t code = calcConstProject(pProj, &pNew);
    if (TSDB_CODE_SUCCESS == code) {
      REPLACE_NODE(pNew);
    } else {
      return code;
    }
    WHERE_NEXT;
X
Xiaoyu Wang 已提交
233
  }
234 235 236
  if (0 == LIST_LENGTH(pSelect->pProjectionList)) {
    return nodesListStrictAppend(pSelect->pProjectionList, createConstantValue());
  }
237 238 239
  return TSDB_CODE_SUCCESS;
}

240 241 242 243 244 245 246 247 248 249 250 251
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 已提交
252
    NODES_DESTORY_LIST(pSelect->pGroupByList);
253 254 255 256
  }
  return code;
}

257 258 259 260 261
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 已提交
262
  int32_t code = calcConstFromTable(pCxt, pSelect->pFromTable);
263
  if (TSDB_CODE_SUCCESS == code) {
X
Xiaoyu Wang 已提交
264
    code = calcConstProjections(pCxt, pSelect, subquery);
X
Xiaoyu Wang 已提交
265
  }
266
  if (TSDB_CODE_SUCCESS == code) {
X
Xiaoyu Wang 已提交
267
    code = calcConstStmtCondition(pCxt, &pSelect->pWhere, &pSelect->isEmptyResult);
X
Xiaoyu Wang 已提交
268
  }
269 270
  if (TSDB_CODE_SUCCESS == code) {
    code = calcConstList(pSelect->pPartitionByList);
X
Xiaoyu Wang 已提交
271
  }
272 273
  if (TSDB_CODE_SUCCESS == code) {
    code = calcConstNode(&pSelect->pWindow);
X
Xiaoyu Wang 已提交
274
  }
275
  if (TSDB_CODE_SUCCESS == code) {
276
    code = calcConstGroupBy(pCxt, pSelect);
277 278
  }
  if (TSDB_CODE_SUCCESS == code) {
X
Xiaoyu Wang 已提交
279
    code = calcConstStmtCondition(pCxt, &pSelect->pHaving, &pSelect->isEmptyResult);
280 281 282 283 284
  }
  if (TSDB_CODE_SUCCESS == code) {
    code = calcConstList(pSelect->pOrderByList);
  }
  return code;
X
Xiaoyu Wang 已提交
285 286
}

287 288 289 290 291 292 293 294
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 已提交
295 296 297 298 299 300 301 302
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;
}

303 304
static int32_t calcConstQuery(SCalcConstContext* pCxt, SNode* pStmt, bool subquery) {
  int32_t code = TSDB_CODE_SUCCESS;
X
Xiaoyu Wang 已提交
305 306
  switch (nodeType(pStmt)) {
    case QUERY_NODE_SELECT_STMT:
307 308
      code = calcConstSelect(pCxt, (SSelectStmt*)pStmt, subquery);
      break;
D
dapan1121 已提交
309
    case QUERY_NODE_EXPLAIN_STMT:
310 311 312 313
      code = calcConstQuery(pCxt, ((SExplainStmt*)pStmt)->pQuery, subquery);
      break;
    case QUERY_NODE_SET_OPERATOR: {
      SSetOperator* pSetOp = (SSetOperator*)pStmt;
314
      code = calcConstQuery(pCxt, pSetOp->pLeft, false);
315
      if (TSDB_CODE_SUCCESS == code) {
316
        code = calcConstQuery(pCxt, pSetOp->pRight, false);
317 318 319
      }
      break;
    }
X
Xiaoyu Wang 已提交
320 321 322
    case QUERY_NODE_DELETE_STMT:
      code = calcConstDelete(pCxt, (SDeleteStmt*)pStmt);
      break;
X
Xiaoyu Wang 已提交
323 324 325
    default:
      break;
  }
326
  return code;
X
Xiaoyu Wang 已提交
327 328
}

X
Xiaoyu Wang 已提交
329
static bool isEmptyResultQuery(SNode* pStmt) {
330
  bool isEmptyResult = false;
X
Xiaoyu Wang 已提交
331 332
  switch (nodeType(pStmt)) {
    case QUERY_NODE_SELECT_STMT:
333 334
      isEmptyResult = ((SSelectStmt*)pStmt)->isEmptyResult;
      break;
X
Xiaoyu Wang 已提交
335
    case QUERY_NODE_EXPLAIN_STMT:
336 337 338 339 340 341 342 343 344 345
      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 已提交
346 347 348
    default:
      break;
  }
349
  return isEmptyResult;
X
Xiaoyu Wang 已提交
350 351
}

X
Xiaoyu Wang 已提交
352
int32_t calculateConstant(SParseContext* pParseCxt, SQuery* pQuery) {
X
Xiaoyu Wang 已提交
353 354 355 356 357
  SCalcConstContext cxt = {.pParseCxt = pParseCxt,
                           .msgBuf.buf = pParseCxt->pMsg,
                           .msgBuf.len = pParseCxt->msgLen,
                           .code = TSDB_CODE_SUCCESS};
  int32_t           code = calcConstQuery(&cxt, pQuery->pRoot, false);
358 359
  if (TSDB_CODE_SUCCESS == code && isEmptyResultQuery(pQuery->pRoot)) {
    pQuery->execMode = QUERY_EXEC_MODE_EMPTY_RESULT;
X
Xiaoyu Wang 已提交
360 361
  }
  return code;
X
Xiaoyu Wang 已提交
362
}