parCalcConst.c 11.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) {
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);
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 204
static bool isUselessCol(SExprNode* pProj) {
  if (QUERY_NODE_FUNCTION == nodeType(pProj) && !fmIsScalarFunc(((SFunctionNode*)pProj)->funcId)) {
205 206 207 208 209
    return false;
  }
  return NULL == ((SExprNode*)pProj)->pAssociation;
}

210 211 212 213 214 215 216 217 218 219 220 221 222
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;
}

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

245 246 247 248 249 250 251 252 253 254 255 256
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 已提交
257
    NODES_DESTORY_LIST(pSelect->pGroupByList);
258 259 260 261
  }
  return code;
}

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

292 293 294 295 296 297 298 299
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 已提交
300 301 302 303 304 305 306 307
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;
}

308 309 310 311 312 313 314 315
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;
}

316 317
static int32_t calcConstQuery(SCalcConstContext* pCxt, SNode* pStmt, bool subquery) {
  int32_t code = TSDB_CODE_SUCCESS;
X
Xiaoyu Wang 已提交
318 319
  switch (nodeType(pStmt)) {
    case QUERY_NODE_SELECT_STMT:
320 321
      code = calcConstSelect(pCxt, (SSelectStmt*)pStmt, subquery);
      break;
D
dapan1121 已提交
322
    case QUERY_NODE_EXPLAIN_STMT:
323 324 325 326
      code = calcConstQuery(pCxt, ((SExplainStmt*)pStmt)->pQuery, subquery);
      break;
    case QUERY_NODE_SET_OPERATOR: {
      SSetOperator* pSetOp = (SSetOperator*)pStmt;
327
      code = calcConstQuery(pCxt, pSetOp->pLeft, false);
328
      if (TSDB_CODE_SUCCESS == code) {
329
        code = calcConstQuery(pCxt, pSetOp->pRight, false);
330 331 332
      }
      break;
    }
X
Xiaoyu Wang 已提交
333 334 335
    case QUERY_NODE_DELETE_STMT:
      code = calcConstDelete(pCxt, (SDeleteStmt*)pStmt);
      break;
336 337 338
    case QUERY_NODE_INSERT_STMT:
      code = calcConstInsert(pCxt, (SInsertStmt*)pStmt);
      break;
X
Xiaoyu Wang 已提交
339 340 341
    default:
      break;
  }
342
  return code;
X
Xiaoyu Wang 已提交
343 344
}

X
Xiaoyu Wang 已提交
345
static bool isEmptyResultQuery(SNode* pStmt) {
346
  bool isEmptyResult = false;
X
Xiaoyu Wang 已提交
347 348
  switch (nodeType(pStmt)) {
    case QUERY_NODE_SELECT_STMT:
349 350
      isEmptyResult = ((SSelectStmt*)pStmt)->isEmptyResult;
      break;
X
Xiaoyu Wang 已提交
351
    case QUERY_NODE_EXPLAIN_STMT:
352 353 354 355 356 357 358 359 360 361
      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 已提交
362 363 364
    default:
      break;
  }
365
  return isEmptyResult;
X
Xiaoyu Wang 已提交
366 367
}

X
Xiaoyu Wang 已提交
368
int32_t calculateConstant(SParseContext* pParseCxt, SQuery* pQuery) {
X
Xiaoyu Wang 已提交
369 370 371 372 373
  SCalcConstContext cxt = {.pParseCxt = pParseCxt,
                           .msgBuf.buf = pParseCxt->pMsg,
                           .msgBuf.len = pParseCxt->msgLen,
                           .code = TSDB_CODE_SUCCESS};
  int32_t           code = calcConstQuery(&cxt, pQuery->pRoot, false);
374 375
  if (TSDB_CODE_SUCCESS == code && isEmptyResultQuery(pQuery->pRoot)) {
    pQuery->execMode = QUERY_EXEC_MODE_EMPTY_RESULT;
X
Xiaoyu Wang 已提交
376 377
  }
  return code;
X
Xiaoyu Wang 已提交
378
}