planTestUtil.cpp 12.6 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
/*
 * 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/>.
 */

#include "planTestUtil.h"
X
Xiaoyu Wang 已提交
17

wafwerar's avatar
wafwerar 已提交
18
#include <getopt.h>
19 20

#include <algorithm>
X
Xiaoyu Wang 已提交
21
#include <array>
22 23

#include "cmdnodes.h"
X
Xiaoyu Wang 已提交
24
#include "mockCatalogService.h"
25 26 27 28 29 30
#include "parser.h"
#include "planInt.h"

using namespace std;
using namespace testing;

X
Xiaoyu Wang 已提交
31 32 33 34 35 36 37 38
#define DO_WITH_THROW(func, ...)                                                                                   \
  do {                                                                                                             \
    int32_t code__ = func(__VA_ARGS__);                                                                            \
    if (TSDB_CODE_SUCCESS != code__) {                                                                             \
      throw runtime_error("sql:[" + stmtEnv_.sql_ + "] " #func " code:" + to_string(code__) +                      \
                          ", strerror:" + string(tstrerror(code__)) + ", msg:" + string(stmtEnv_.msgBuf_.data())); \
    }                                                                                                              \
  } while (0);
39

X
Xiaoyu Wang 已提交
40 41 42 43 44 45 46 47 48 49 50 51 52
enum DumpModule {
  DUMP_MODULE_NOTHING = 1,
  DUMP_MODULE_PARSER,
  DUMP_MODULE_LOGIC,
  DUMP_MODULE_OPTIMIZED,
  DUMP_MODULE_SPLIT,
  DUMP_MODULE_SCALED,
  DUMP_MODULE_PHYSICAL,
  DUMP_MODULE_SUBPLAN,
  DUMP_MODULE_ALL
};

DumpModule g_dumpModule = DUMP_MODULE_NOTHING;
53
int32_t    g_skipSql = 0;
54
int32_t    g_logLevel = 131;
X
Xiaoyu Wang 已提交
55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76

void setDumpModule(const char* pModule) {
  if (NULL == pModule) {
    g_dumpModule = DUMP_MODULE_ALL;
  } else if (0 == strncasecmp(pModule, "parser", strlen(pModule))) {
    g_dumpModule = DUMP_MODULE_PARSER;
  } else if (0 == strncasecmp(pModule, "logic", strlen(pModule))) {
    g_dumpModule = DUMP_MODULE_LOGIC;
  } else if (0 == strncasecmp(pModule, "optimized", strlen(pModule))) {
    g_dumpModule = DUMP_MODULE_OPTIMIZED;
  } else if (0 == strncasecmp(pModule, "split", strlen(pModule))) {
    g_dumpModule = DUMP_MODULE_SPLIT;
  } else if (0 == strncasecmp(pModule, "scaled", strlen(pModule))) {
    g_dumpModule = DUMP_MODULE_SCALED;
  } else if (0 == strncasecmp(pModule, "physical", strlen(pModule))) {
    g_dumpModule = DUMP_MODULE_PHYSICAL;
  } else if (0 == strncasecmp(pModule, "subplan", strlen(pModule))) {
    g_dumpModule = DUMP_MODULE_SUBPLAN;
  } else if (0 == strncasecmp(pModule, "all", strlen(pModule))) {
    g_dumpModule = DUMP_MODULE_PHYSICAL;
  }
}
X
Xiaoyu Wang 已提交
77

wafwerar's avatar
wafwerar 已提交
78
void setSkipSqlNum(const char* pNum) { g_skipSql = stoi(pNum); }
79 80 81 82 83

void setLogLevel(const char* pLogLevel) { g_logLevel = stoi(pLogLevel); }

int32_t getLogLevel() { return g_logLevel; }

84
class PlannerTestBaseImpl {
X
Xiaoyu Wang 已提交
85
 public:
86 87
  PlannerTestBaseImpl() : sqlNo_(0) {}

88 89 90
  void useDb(const string& acctId, const string& db) {
    caseEnv_.acctId_ = acctId;
    caseEnv_.db_ = db;
91
    caseEnv_.nsql_ = g_skipSql;
92 93 94
  }

  void run(const string& sql) {
95
    ++sqlNo_;
96 97 98 99 100
    if (caseEnv_.nsql_ > 0) {
      --(caseEnv_.nsql_);
      return;
    }

101 102 103 104 105 106 107 108
    reset();
    try {
      SQuery* pQuery = nullptr;
      doParseSql(sql, &pQuery);

      SPlanContext cxt = {0};
      setPlanContext(pQuery, &cxt);

X
Xiaoyu Wang 已提交
109 110
      SLogicSubplan* pLogicSubplan = nullptr;
      doCreateLogicPlan(&cxt, &pLogicSubplan);
111

X
Xiaoyu Wang 已提交
112
      doOptimizeLogicPlan(&cxt, pLogicSubplan);
113

X
Xiaoyu Wang 已提交
114
      doSplitLogicPlan(&cxt, pLogicSubplan);
115 116 117 118 119

      SQueryLogicPlan* pLogicPlan = nullptr;
      doScaleOutLogicPlan(&cxt, pLogicSubplan, &pLogicPlan);

      SQueryPlan* pPlan = nullptr;
X
Xiaoyu Wang 已提交
120
      doCreatePhysiPlan(&cxt, pLogicPlan, &pPlan);
X
Xiaoyu Wang 已提交
121

X
Xiaoyu Wang 已提交
122
      dump(g_dumpModule);
123
    } catch (...) {
X
Xiaoyu Wang 已提交
124
      dump(DUMP_MODULE_ALL);
125 126 127 128
      throw;
    }
  }

129
  void prepare(const string& sql) {
130 131 132 133
    if (caseEnv_.nsql_ > 0) {
      return;
    }

134 135 136 137 138 139 140 141 142 143
    reset();
    try {
      doParseSql(sql, &stmtEnv_.pQuery_, true);
    } catch (...) {
      dump(DUMP_MODULE_ALL);
      throw;
    }
  }

  void bindParams(TAOS_MULTI_BIND* pParams, int32_t colIdx) {
144 145 146 147
    if (caseEnv_.nsql_ > 0) {
      return;
    }

148 149
    try {
      doBindParams(stmtEnv_.pQuery_, pParams, colIdx);
150 151 152 153 154 155 156
    } catch (...) {
      dump(DUMP_MODULE_ALL);
      throw;
    }
  }

  void exec() {
157 158 159 160 161
    if (caseEnv_.nsql_ > 0) {
      --(caseEnv_.nsql_);
      return;
    }

162 163
    try {
      doParseBoundSql(stmtEnv_.pQuery_);
164 165 166 167

      SPlanContext cxt = {0};
      setPlanContext(stmtEnv_.pQuery_, &cxt);

X
Xiaoyu Wang 已提交
168 169
      SLogicSubplan* pLogicSubplan = nullptr;
      doCreateLogicPlan(&cxt, &pLogicSubplan);
170

X
Xiaoyu Wang 已提交
171
      doOptimizeLogicPlan(&cxt, pLogicSubplan);
172

X
Xiaoyu Wang 已提交
173
      doSplitLogicPlan(&cxt, pLogicSubplan);
174 175 176 177 178 179 180 181 182 183 184 185 186 187

      SQueryLogicPlan* pLogicPlan = nullptr;
      doScaleOutLogicPlan(&cxt, pLogicSubplan, &pLogicPlan);

      SQueryPlan* pPlan = nullptr;
      doCreatePhysiPlan(&cxt, pLogicPlan, &pPlan);

      dump(g_dumpModule);
    } catch (...) {
      dump(DUMP_MODULE_ALL);
      throw;
    }
  }

X
Xiaoyu Wang 已提交
188
 private:
189
  struct caseEnv {
190 191 192
    string  acctId_;
    string  db_;
    int32_t nsql_;
193 194

    caseEnv() : nsql_(0) {}
195 196 197
  };

  struct stmtEnv {
X
Xiaoyu Wang 已提交
198
    string            sql_;
199
    array<char, 1024> msgBuf_;
200 201
    SQuery*           pQuery_;

202
    stmtEnv() : pQuery_(nullptr) {}
203
    ~stmtEnv() { qDestroyQuery(pQuery_); }
204 205 206
  };

  struct stmtRes {
X
Xiaoyu Wang 已提交
207
    string         ast_;
208 209
    string         prepareAst_;
    string         boundAst_;
X
Xiaoyu Wang 已提交
210 211 212 213 214
    string         rawLogicPlan_;
    string         optimizedLogicPlan_;
    string         splitLogicPlan_;
    string         scaledLogicPlan_;
    string         physiPlan_;
X
Xiaoyu Wang 已提交
215
    vector<string> physiSubplans_;
216 217 218 219 220
  };

  void reset() {
    stmtEnv_.sql_.clear();
    stmtEnv_.msgBuf_.fill(0);
221
    qDestroyQuery(stmtEnv_.pQuery_);
222 223

    res_.ast_.clear();
224
    res_.boundAst_.clear();
225 226 227 228 229
    res_.rawLogicPlan_.clear();
    res_.optimizedLogicPlan_.clear();
    res_.splitLogicPlan_.clear();
    res_.scaledLogicPlan_.clear();
    res_.physiPlan_.clear();
230
    res_.physiSubplans_.clear();
231 232
  }

X
Xiaoyu Wang 已提交
233 234 235 236 237
  void dump(DumpModule module) {
    if (DUMP_MODULE_NOTHING == module) {
      return;
    }

238
    cout << "========================================== " << sqlNo_ << " sql : [" << stmtEnv_.sql_ << "]" << endl;
X
Xiaoyu Wang 已提交
239 240

    if (DUMP_MODULE_ALL == module || DUMP_MODULE_PARSER == module) {
241
      if (res_.prepareAst_.empty()) {
X
Xiaoyu Wang 已提交
242
        cout << "+++++++++++++++++++++syntax tree : " << endl;
243 244
        cout << res_.ast_ << endl;
      } else {
X
Xiaoyu Wang 已提交
245
        cout << "+++++++++++++++++++++prepare syntax tree : " << endl;
246
        cout << res_.prepareAst_ << endl;
X
Xiaoyu Wang 已提交
247
        cout << "+++++++++++++++++++++bound syntax tree : " << endl;
248
        cout << res_.boundAst_ << endl;
X
Xiaoyu Wang 已提交
249
        cout << "+++++++++++++++++++++syntax tree : " << endl;
250 251
        cout << res_.ast_ << endl;
      }
X
Xiaoyu Wang 已提交
252 253 254
    }

    if (DUMP_MODULE_ALL == module || DUMP_MODULE_LOGIC == module) {
X
Xiaoyu Wang 已提交
255
      cout << "+++++++++++++++++++++raw logic plan : " << endl;
X
Xiaoyu Wang 已提交
256 257 258 259
      cout << res_.rawLogicPlan_ << endl;
    }

    if (DUMP_MODULE_ALL == module || DUMP_MODULE_OPTIMIZED == module) {
X
Xiaoyu Wang 已提交
260
      cout << "+++++++++++++++++++++optimized logic plan : " << endl;
X
Xiaoyu Wang 已提交
261 262 263 264
      cout << res_.optimizedLogicPlan_ << endl;
    }

    if (DUMP_MODULE_ALL == module || DUMP_MODULE_SPLIT == module) {
X
Xiaoyu Wang 已提交
265
      cout << "+++++++++++++++++++++split logic plan : " << endl;
X
Xiaoyu Wang 已提交
266 267 268 269
      cout << res_.splitLogicPlan_ << endl;
    }

    if (DUMP_MODULE_ALL == module || DUMP_MODULE_SCALED == module) {
X
Xiaoyu Wang 已提交
270
      cout << "+++++++++++++++++++++scaled logic plan : " << endl;
X
Xiaoyu Wang 已提交
271 272 273 274
      cout << res_.scaledLogicPlan_ << endl;
    }

    if (DUMP_MODULE_ALL == module || DUMP_MODULE_PHYSICAL == module) {
X
Xiaoyu Wang 已提交
275
      cout << "+++++++++++++++++++++physical plan : " << endl;
X
Xiaoyu Wang 已提交
276 277 278 279
      cout << res_.physiPlan_ << endl;
    }

    if (DUMP_MODULE_ALL == module || DUMP_MODULE_SUBPLAN == module) {
X
Xiaoyu Wang 已提交
280
      cout << "+++++++++++++++++++++physical subplan : " << endl;
X
Xiaoyu Wang 已提交
281 282 283
      for (const auto& subplan : res_.physiSubplans_) {
        cout << subplan << endl;
      }
X
Xiaoyu Wang 已提交
284
    }
285
  }
X
Xiaoyu Wang 已提交
286

287
  void doParseSql(const string& sql, SQuery** pQuery, bool prepare = false) {
288 289
    stmtEnv_.sql_ = sql;
    transform(stmtEnv_.sql_.begin(), stmtEnv_.sql_.end(), stmtEnv_.sql_.begin(), ::tolower);
X
Xiaoyu Wang 已提交
290

291 292 293 294 295 296 297
    SParseContext cxt = {0};
    cxt.acctId = atoi(caseEnv_.acctId_.c_str());
    cxt.db = caseEnv_.db_.c_str();
    cxt.pSql = stmtEnv_.sql_.c_str();
    cxt.sqlLen = stmtEnv_.sql_.length();
    cxt.pMsg = stmtEnv_.msgBuf_.data();
    cxt.msgLen = stmtEnv_.msgBuf_.max_size();
X
Xiaoyu Wang 已提交
298

X
Xiaoyu Wang 已提交
299
    DO_WITH_THROW(qParseSql, &cxt, pQuery);
300
    if (prepare) {
301
      res_.prepareAst_ = toString((*pQuery)->pPrepareRoot);
302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324
    } else {
      res_.ast_ = toString((*pQuery)->pRoot);
    }
  }

  void doBindParams(SQuery* pQuery, TAOS_MULTI_BIND* pParams, int32_t colIdx) {
    DO_WITH_THROW(qStmtBindParams, pQuery, pParams, colIdx);
    if (colIdx < 0 || pQuery->placeholderNum == colIdx + 1) {
      res_.boundAst_ = toString(pQuery->pRoot);
    }
  }

  void doParseBoundSql(SQuery* pQuery) {
    SParseContext cxt = {0};
    cxt.acctId = atoi(caseEnv_.acctId_.c_str());
    cxt.db = caseEnv_.db_.c_str();
    cxt.pSql = stmtEnv_.sql_.c_str();
    cxt.sqlLen = stmtEnv_.sql_.length();
    cxt.pMsg = stmtEnv_.msgBuf_.data();
    cxt.msgLen = stmtEnv_.msgBuf_.max_size();

    DO_WITH_THROW(qStmtParseQuerySql, &cxt, pQuery);
    res_.ast_ = toString(pQuery->pRoot);
325 326
  }

X
Xiaoyu Wang 已提交
327 328 329
  void doCreateLogicPlan(SPlanContext* pCxt, SLogicSubplan** pLogicSubplan) {
    DO_WITH_THROW(createLogicPlan, pCxt, pLogicSubplan);
    res_.rawLogicPlan_ = toString((SNode*)(*pLogicSubplan));
330 331
  }

X
Xiaoyu Wang 已提交
332 333 334
  void doOptimizeLogicPlan(SPlanContext* pCxt, SLogicSubplan* pLogicSubplan) {
    DO_WITH_THROW(optimizeLogicPlan, pCxt, pLogicSubplan);
    res_.optimizedLogicPlan_ = toString((SNode*)pLogicSubplan);
335 336
  }

X
Xiaoyu Wang 已提交
337 338 339
  void doSplitLogicPlan(SPlanContext* pCxt, SLogicSubplan* pLogicSubplan) {
    DO_WITH_THROW(splitLogicPlan, pCxt, pLogicSubplan);
    res_.splitLogicPlan_ = toString((SNode*)(pLogicSubplan));
340 341 342 343 344 345 346
  }

  void doScaleOutLogicPlan(SPlanContext* pCxt, SLogicSubplan* pLogicSubplan, SQueryLogicPlan** pLogicPlan) {
    DO_WITH_THROW(scaleOutLogicPlan, pCxt, pLogicSubplan, pLogicPlan);
    res_.scaledLogicPlan_ = toString((SNode*)(*pLogicPlan));
  }

X
Xiaoyu Wang 已提交
347 348
  void doCreatePhysiPlan(SPlanContext* pCxt, SQueryLogicPlan* pLogicPlan, SQueryPlan** pPlan) {
    SArray* pExecNodeList = taosArrayInit(TARRAY_MIN_SIZE, sizeof(SQueryNodeAddr));
349 350
    DO_WITH_THROW(createPhysiPlan, pCxt, pLogicPlan, pPlan, pExecNodeList);
    res_.physiPlan_ = toString((SNode*)(*pPlan));
X
Xiaoyu Wang 已提交
351 352 353
    SNode* pNode;
    FOREACH(pNode, (*pPlan)->pSubplans) {
      SNode* pSubplan;
X
Xiaoyu Wang 已提交
354
      FOREACH(pSubplan, ((SNodeListNode*)pNode)->pNodeList) { res_.physiSubplans_.push_back(toString(pSubplan)); }
X
Xiaoyu Wang 已提交
355
    }
356 357 358
  }

  void setPlanContext(SQuery* pQuery, SPlanContext* pCxt) {
359
    pCxt->queryId = 1;
360 361 362 363 364 365
    if (QUERY_NODE_CREATE_TOPIC_STMT == nodeType(pQuery->pRoot)) {
      pCxt->pAstRoot = ((SCreateTopicStmt*)pQuery->pRoot)->pQuery;
      pCxt->topicQuery = true;
    } else if (QUERY_NODE_CREATE_INDEX_STMT == nodeType(pQuery->pRoot)) {
      SMCreateSmaReq req = {0};
      tDeserializeSMCreateSmaReq(pQuery->pCmdMsg->pMsg, pQuery->pCmdMsg->msgLen, &req);
X
Xiaoyu Wang 已提交
366
      g_mockCatalogService->createSmaIndex(&req);
367 368 369 370 371 372 373 374 375 376 377 378 379 380
      nodesStringToNode(req.ast, &pCxt->pAstRoot);
      pCxt->streamQuery = true;
    } else if (QUERY_NODE_CREATE_STREAM_STMT == nodeType(pQuery->pRoot)) {
      SCreateStreamStmt* pStmt = (SCreateStreamStmt*)pQuery->pRoot;
      pCxt->pAstRoot = pStmt->pQuery;
      pCxt->streamQuery = true;
      pCxt->triggerType = pStmt->pOptions->triggerType;
      pCxt->watermark = (NULL != pStmt->pOptions->pWatermark ? ((SValueNode*)pStmt->pOptions->pWatermark)->datum.i : 0);
    } else {
      pCxt->pAstRoot = pQuery->pRoot;
    }
  }

  string toString(const SNode* pRoot) {
X
Xiaoyu Wang 已提交
381
    char*   pStr = NULL;
382 383 384 385 386 387 388 389 390 391
    int32_t len = 0;
    DO_WITH_THROW(nodesNodeToString, pRoot, false, &pStr, &len)
    string str(pStr);
    taosMemoryFreeClear(pStr);
    return str;
  }

  caseEnv caseEnv_;
  stmtEnv stmtEnv_;
  stmtRes res_;
392
  int32_t sqlNo_;
393 394
};

X
Xiaoyu Wang 已提交
395
PlannerTestBase::PlannerTestBase() : impl_(new PlannerTestBaseImpl()) {}
396

X
Xiaoyu Wang 已提交
397
PlannerTestBase::~PlannerTestBase() {}
398

X
Xiaoyu Wang 已提交
399
void PlannerTestBase::useDb(const std::string& acctId, const std::string& db) { impl_->useDb(acctId, db); }
400

X
Xiaoyu Wang 已提交
401
void PlannerTestBase::run(const std::string& sql) { return impl_->run(sql); }
402 403 404 405 406 407 408 409

void PlannerTestBase::prepare(const std::string& sql) { return impl_->prepare(sql); }

void PlannerTestBase::bindParams(TAOS_MULTI_BIND* pParams, int32_t colIdx) {
  return impl_->bindParams(pParams, colIdx);
}

void PlannerTestBase::exec() { return impl_->exec(); }