parserAstTest.cpp 12.4 KB
Newer Older
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/>.
 */

16 17 18
#include <algorithm>
#include <string>

19 20
#include <gtest/gtest.h>

X
Xiaoyu Wang 已提交
21
#include "parInt.h"
22 23 24 25

using namespace std;
using namespace testing;

X
Xiaoyu Wang 已提交
26
class ParserTest : public Test {
27 28 29 30 31 32 33 34 35
protected:
  void setDatabase(const string& acctId, const string& db) {
    acctId_ = acctId;
    db_ = db;
  }

  void bind(const char* sql) {
    reset();
    cxt_.acctId = atoi(acctId_.c_str());
36 37 38
    cxt_.db = db_.c_str();
    sqlBuf_ = string(sql);
    transform(sqlBuf_.begin(), sqlBuf_.end(), sqlBuf_.begin(), ::tolower);
39
    cxt_.sqlLen = strlen(sql);
40
    cxt_.pSql = sqlBuf_.c_str();
41 42
  }

43
  bool run(int32_t parseCode = TSDB_CODE_SUCCESS, int32_t translateCode = TSDB_CODE_SUCCESS) {
44 45
    int32_t code = doParse(&cxt_, &query_);
    if (code != TSDB_CODE_SUCCESS) {
46
      cout << "sql:[" << cxt_.pSql << "] parser code:" << tstrerror(code) << ", msg:" << errMagBuf_ << endl;
47 48 49 50 51
      return (TSDB_CODE_SUCCESS != parseCode);
    }
    if (TSDB_CODE_SUCCESS != parseCode) {
      return false;
    }
52
    string parserStr = toString(query_->pRoot);
X
Xiaoyu Wang 已提交
53
    code = doTranslate(&cxt_, query_);
54
    if (code != TSDB_CODE_SUCCESS) {
55
      cout << "sql:[" << cxt_.pSql << "] translate code:" << code << ", " << translateCode << ", msg:" << errMagBuf_ << endl;
56
      return (code == translateCode);
57
    }
58 59 60 61 62
    cout << "input sql : [" << cxt_.pSql << "]" << endl;
    cout << "parser output: " << endl;
    cout << parserStr << endl;
    cout << "translate output: " << endl;
    cout << toString(query_->pRoot) << endl;
63
    return (TSDB_CODE_SUCCESS == translateCode);
64 65 66 67 68
  }

private:
  static const int max_err_len = 1024;

69 70 71 72 73 74 75
  string toString(const SNode* pRoot, bool format = false) {
    char* pStr = NULL;
    int32_t len = 0;
    int32_t code = nodesNodeToString(pRoot, format, &pStr, &len);
    if (code != TSDB_CODE_SUCCESS) {
      cout << "sql:[" << cxt_.pSql << "] toString code:" << code << ", strerror:" << tstrerror(code) << endl;
      throw "nodesNodeToString failed!";
76
    }
77 78 79
    string str(pStr);
    tfree(pStr);
    return str;
80 81 82 83 84 85 86 87 88 89 90 91
  }

  void reset() {
    memset(&cxt_, 0, sizeof(cxt_));
    memset(errMagBuf_, 0, max_err_len);
    cxt_.pMsg = errMagBuf_;
    cxt_.msgLen = max_err_len;
  }

  string acctId_;
  string db_;
  char errMagBuf_[max_err_len];
92
  string sqlBuf_;
93
  SParseContext cxt_;
X
Xiaoyu Wang 已提交
94
  SQuery* query_;
95 96
};

X
Xiaoyu Wang 已提交
97
TEST_F(ParserTest, selectSimple) {
98 99 100
  setDatabase("root", "test");

  bind("SELECT * FROM t1");
101
  ASSERT_TRUE(run());
102 103

  bind("SELECT * FROM test.t1");
104
  ASSERT_TRUE(run());
105

106
  bind("SELECT ts, c1 FROM t1");
107 108
  ASSERT_TRUE(run());

109 110 111 112
  bind("SELECT ts, t.c1 FROM (SELECT * FROM t1) t");
  ASSERT_TRUE(run());

  bind("SELECT * FROM t1 tt1, t1 tt2 WHERE tt1.c1 = tt2.c1");
113
  ASSERT_TRUE(run());
114 115
}

X
Xiaoyu Wang 已提交
116
TEST_F(ParserTest, selectConstant) {
117 118 119 120 121 122 123 124 125
  setDatabase("root", "test");

  bind("SELECT 123, 20.4, 'abc', \"wxy\", TIMESTAMP '2022-02-09 17:30:20', true, false, 10s FROM t1");
  ASSERT_TRUE(run());

  bind("SELECT 1234567890123456789012345678901234567890, 20.1234567890123456789012345678901234567890, 'abc', \"wxy\", TIMESTAMP '2022-02-09 17:30:20', true, false, 15s FROM t1");
  ASSERT_TRUE(run());
}

X
Xiaoyu Wang 已提交
126
TEST_F(ParserTest, selectExpression) {
127 128
  setDatabase("root", "test");

129
  bind("SELECT ts + 10s, c1 + 10, concat(c2, 'abc') FROM t1");
130
  ASSERT_TRUE(run());
131 132 133 134 135 136

  bind("SELECT ts > 0, c1 < 20 AND c2 = 'qaz' FROM t1");
  ASSERT_TRUE(run());

  bind("SELECT ts > 0, c1 BETWEEN 10 AND 20 AND c2 = 'qaz' FROM t1");
  ASSERT_TRUE(run());
137 138
}

X
Xiaoyu Wang 已提交
139
TEST_F(ParserTest, selectClause) {
140 141
  setDatabase("root", "test");

142
  // GROUP BY clause
143
  bind("SELECT count(*) cnt FROM t1 WHERE c1 > 0");
144 145 146 147 148 149 150 151 152 153 154 155 156 157 158
  ASSERT_TRUE(run());

  bind("SELECT count(*), c2 cnt FROM t1 WHERE c1 > 0 GROUP BY c2");
  ASSERT_TRUE(run());

  bind("SELECT count(*) cnt FROM t1 WHERE c1 > 0 GROUP BY c2 HAVING count(c1) > 10");
  ASSERT_TRUE(run());

  bind("SELECT count(*), c1, c2 + 10, c1 + c2 cnt FROM t1 WHERE c1 > 0 GROUP BY c2, c1");
  ASSERT_TRUE(run());

  bind("SELECT count(*), c1 + 10, c2 cnt FROM t1 WHERE c1 > 0 GROUP BY c1 + 10, c2");
  ASSERT_TRUE(run());

  // ORDER BY clause
159 160 161 162 163
  bind("SELECT count(*) cnt FROM t1 WHERE c1 > 0 GROUP BY c2 ORDER BY cnt");
  ASSERT_TRUE(run());

  bind("SELECT count(*) cnt FROM t1 WHERE c1 > 0 GROUP BY c2 ORDER BY 1");
  ASSERT_TRUE(run());
164 165 166 167 168 169 170 171 172 173

  // DISTINCT clause
  bind("SELECT DISTINCT c1, c2 FROM t1 WHERE c1 > 0 ORDER BY c1");
  ASSERT_TRUE(run());

  bind("SELECT DISTINCT c1 + 10, c2 FROM t1 WHERE c1 > 0 ORDER BY c1 + 10, c2");
  ASSERT_TRUE(run());

  bind("SELECT DISTINCT c1 + 10 cc1, c2 cc2 FROM t1 WHERE c1 > 0 ORDER BY cc1, c2");
  ASSERT_TRUE(run());
174 175 176

  bind("SELECT DISTINCT count(c2) FROM t1 WHERE c1 > 0 GROUP BY c1 ORDER BY count(c2)");
  ASSERT_TRUE(run());
177 178
}

X
Xiaoyu Wang 已提交
179
TEST_F(ParserTest, selectSyntaxError) {
180 181 182 183 184 185 186 187 188 189 190 191 192
  setDatabase("root", "test");

  bind("SELECTT * FROM t1");
  ASSERT_TRUE(run(TSDB_CODE_FAILED));

  bind("SELECT *");
  ASSERT_TRUE(run(TSDB_CODE_FAILED));

  bind("SELECT *, * FROM test.t1");
  ASSERT_TRUE(run(TSDB_CODE_FAILED));

  bind("SELECT * FROM test.t1 t WHER");
  ASSERT_TRUE(run(TSDB_CODE_FAILED));
193
}
194

X
Xiaoyu Wang 已提交
195
TEST_F(ParserTest, selectSemanticError) {
196 197
  setDatabase("root", "test");

198
  // TSDB_CODE_PAR_INVALID_COLUMN
199
  bind("SELECT c1, cc1 FROM t1");
200 201
  ASSERT_TRUE(run(TSDB_CODE_SUCCESS, TSDB_CODE_PAR_INVALID_COLUMN));

202
  bind("SELECT t1.c1, t1.cc1 FROM t1");
203 204 205
  ASSERT_TRUE(run(TSDB_CODE_SUCCESS, TSDB_CODE_PAR_INVALID_COLUMN));

  // TSDB_CODE_PAR_TABLE_NOT_EXIST
206
  bind("SELECT * FROM t10");
207
  ASSERT_TRUE(run(TSDB_CODE_SUCCESS, TSDB_CODE_PAR_TABLE_NOT_EXIST));
208

209 210
  bind("SELECT * FROM test.t10");
  ASSERT_TRUE(run(TSDB_CODE_SUCCESS, TSDB_CODE_PAR_TABLE_NOT_EXIST));
211

212 213 214
  bind("SELECT t2.c1 FROM t1");
  ASSERT_TRUE(run(TSDB_CODE_SUCCESS, TSDB_CODE_PAR_TABLE_NOT_EXIST));

215
  // TSDB_CODE_PAR_AMBIGUOUS_COLUMN
216
  bind("SELECT c2 FROM t1 tt1, t1 tt2 WHERE tt1.c1 = tt2.c1");
217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235
  ASSERT_TRUE(run(TSDB_CODE_SUCCESS, TSDB_CODE_PAR_AMBIGUOUS_COLUMN));

  // TSDB_CODE_PAR_WRONG_VALUE_TYPE
  bind("SELECT 10n FROM t1");
  ASSERT_TRUE(run(TSDB_CODE_SUCCESS, TSDB_CODE_PAR_WRONG_VALUE_TYPE));

  bind("SELECT TIMESTAMP '2010' FROM t1");
  ASSERT_TRUE(run(TSDB_CODE_SUCCESS, TSDB_CODE_PAR_WRONG_VALUE_TYPE));

  // TSDB_CODE_PAR_INVALID_FUNTION
  bind("SELECT cnt(*) FROM t1");
  ASSERT_TRUE(run(TSDB_CODE_SUCCESS, TSDB_CODE_PAR_INVALID_FUNTION));

  // TSDB_CODE_PAR_FUNTION_PARA_NUM
  // TSDB_CODE_PAR_FUNTION_PARA_TYPE

  // TSDB_CODE_PAR_ILLEGAL_USE_AGG_FUNCTION
  bind("SELECT c2 FROM t1 tt1 JOIN t1 tt2 ON count(*) > 0");
  ASSERT_TRUE(run(TSDB_CODE_SUCCESS, TSDB_CODE_PAR_ILLEGAL_USE_AGG_FUNCTION));
236 237

  bind("SELECT c2 FROM t1 where count(*) > 0");
238 239 240 241 242 243 244 245 246 247 248 249
  ASSERT_TRUE(run(TSDB_CODE_SUCCESS, TSDB_CODE_PAR_ILLEGAL_USE_AGG_FUNCTION));

  bind("SELECT c2 FROM t1 GROUP BY count(*)");
  ASSERT_TRUE(run(TSDB_CODE_SUCCESS, TSDB_CODE_PAR_ILLEGAL_USE_AGG_FUNCTION));

  // TSDB_CODE_PAR_WRONG_NUMBER_OF_SELECT
  bind("SELECT c2 FROM t1 ORDER BY 0");
  ASSERT_TRUE(run(TSDB_CODE_SUCCESS, TSDB_CODE_PAR_WRONG_NUMBER_OF_SELECT));

  bind("SELECT c2 FROM t1 ORDER BY 2");
  ASSERT_TRUE(run(TSDB_CODE_SUCCESS, TSDB_CODE_PAR_WRONG_NUMBER_OF_SELECT));

250
  // TSDB_CODE_PAR_GROUPBY_LACK_EXPRESSION
251 252 253 254 255 256 257 258 259 260 261
  bind("SELECT count(*) cnt FROM t1 HAVING c1 > 0");
  ASSERT_TRUE(run(TSDB_CODE_SUCCESS, TSDB_CODE_PAR_GROUPBY_LACK_EXPRESSION));

  bind("SELECT count(*) cnt FROM t1 GROUP BY c2 HAVING c1 > 0");
  ASSERT_TRUE(run(TSDB_CODE_SUCCESS, TSDB_CODE_PAR_GROUPBY_LACK_EXPRESSION));

  bind("SELECT count(*), c1 cnt FROM t1 GROUP BY c2 HAVING c2 > 0");
  ASSERT_TRUE(run(TSDB_CODE_SUCCESS, TSDB_CODE_PAR_GROUPBY_LACK_EXPRESSION));

  bind("SELECT count(*) cnt FROM t1 GROUP BY c2 HAVING c2 > 0 ORDER BY c1");
  ASSERT_TRUE(run(TSDB_CODE_SUCCESS, TSDB_CODE_PAR_GROUPBY_LACK_EXPRESSION));
262 263 264 265 266 267 268 269 270 271 272 273 274 275

  // TSDB_CODE_PAR_NOT_SINGLE_GROUP
  bind("SELECT count(*), c1 FROM t1");
  ASSERT_TRUE(run(TSDB_CODE_SUCCESS, TSDB_CODE_PAR_NOT_SINGLE_GROUP));

  bind("SELECT count(*) FROM t1 ORDER BY c1");
  ASSERT_TRUE(run(TSDB_CODE_SUCCESS, TSDB_CODE_PAR_NOT_SINGLE_GROUP));

  bind("SELECT c1 FROM t1 ORDER BY count(*)");
  ASSERT_TRUE(run(TSDB_CODE_SUCCESS, TSDB_CODE_PAR_NOT_SINGLE_GROUP));

  // TSDB_CODE_PAR_NOT_SELECTED_EXPRESSION
  bind("SELECT DISTINCT c1, c2 FROM t1 WHERE c1 > 0 ORDER BY ts");
  ASSERT_TRUE(run(TSDB_CODE_SUCCESS, TSDB_CODE_PAR_NOT_SELECTED_EXPRESSION));
276 277 278 279 280 281

  bind("SELECT DISTINCT c1 FROM t1 WHERE c1 > 0 ORDER BY count(c2)");
  ASSERT_TRUE(run(TSDB_CODE_SUCCESS, TSDB_CODE_PAR_NOT_SELECTED_EXPRESSION));

  bind("SELECT DISTINCT c2 FROM t1 WHERE c1 > 0 ORDER BY count(c2)");
  ASSERT_TRUE(run(TSDB_CODE_SUCCESS, TSDB_CODE_PAR_NOT_SELECTED_EXPRESSION));
282
}
283

284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300
TEST_F(ParserTest, createUser) {
  setDatabase("root", "test");

  bind("create user wxy pass '123456'");
  ASSERT_TRUE(run());
}

TEST_F(ParserTest, createDnode) {
  setDatabase("root", "test");

  bind("create dnode abc1 port 7000");
  ASSERT_TRUE(run());

  bind("create dnode 1.1.1.1 port 9000");
  ASSERT_TRUE(run());
}

301
TEST_F(ParserTest, createDatabase) {
302 303
  setDatabase("root", "test");

304 305
  bind("create database wxy_db");
  ASSERT_TRUE(run());
306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326

  bind("create database if not exists wxy_db "
       "BLOCKS 100 "
       "CACHE 100 "
       "CACHELAST 2 "
       "COMP 1 "
       "DAYS 100 "
       "FSYNC 100 "
       "MAXROWS 1000 "
       "MINROWS 100 "
       "KEEP 100 "
       "PRECISION 'ms' "
       "QUORUM 1 "
       "REPLICA 3 "
       "TTL 100 "
       "WAL 2 "
       "VGROUPS 100 "
       "SINGLE_STABLE 0 "
       "STREAM_MODE 1 "
      );
  ASSERT_TRUE(run());
327 328 329
}

TEST_F(ParserTest, showDatabase) {
330 331
  setDatabase("root", "test");

332 333 334 335 336
  bind("show databases");
  ASSERT_TRUE(run());
}

TEST_F(ParserTest, useDatabase) {
337 338
  setDatabase("root", "test");

339 340 341 342 343
  bind("use wxy_db");
  ASSERT_TRUE(run());
}

TEST_F(ParserTest, createTable) {
344 345
  setDatabase("root", "test");

346 347
  bind("create table t1(ts timestamp, c1 int)");
  ASSERT_TRUE(run());
348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364

  bind("create table if not exists test.t1("
       "ts TIMESTAMP, c1 INT, c2 INT UNSIGNED, c3 BIGINT, c4 BIGINT UNSIGNED, c5 FLOAT, c6 DOUBLE, c7 BINARY(20), c8 SMALLINT, "
       "c9 SMALLINT UNSIGNED COMMENT 'test column comment', c10 TINYINT, c11 TINYINT UNSIGNED, c12 BOOL, c13 NCHAR(30), c14 JSON, c15 VARCHAR(50)) "
       "KEEP 100 TTL 100 COMMENT 'test create table' SMA(c1, c2, c3)"
      );
  ASSERT_TRUE(run());
  
  bind("create table if not exists test.t1("
       "ts TIMESTAMP, c1 INT, c2 INT UNSIGNED, c3 BIGINT, c4 BIGINT UNSIGNED, c5 FLOAT, c6 DOUBLE, c7 BINARY(20), c8 SMALLINT, "
       "c9 SMALLINT UNSIGNED COMMENT 'test column comment', c10 TINYINT, c11 TINYINT UNSIGNED, c12 BOOL, c13 NCHAR(30), c14 JSON, c15 VARCHAR(50)) "
       "TAGS (tsa TIMESTAMP, a1 INT, a2 INT UNSIGNED, a3 BIGINT, a4 BIGINT UNSIGNED, a5 FLOAT, a6 DOUBLE, a7 BINARY(20), a8 SMALLINT, "
       "a9 SMALLINT UNSIGNED COMMENT 'test column comment', a10 TINYINT, a11 TINYINT UNSIGNED, a12 BOOL, a13 NCHAR(30), a14 JSON, a15 VARCHAR(50)) "
       "KEEP 100 TTL 100 COMMENT 'test create table' SMA(c1, c2, c3)"
      );
  ASSERT_TRUE(run());
  
365
  bind("create table if not exists t1 using st1 tags(1, 'wxy')");
366 367 368
  ASSERT_TRUE(run());

  bind("create table "
369 370 371
       "if not exists test.t1 using test.st1 (tag1, tag2) tags(1, 'abc') "
       "if not exists test.t2 using test.st1 (tag1, tag2) tags(2, 'abc') "
       "if not exists test.t3 using test.st1 (tag1, tag2) tags(3, 'abc')"
372 373
      );
  ASSERT_TRUE(run());
374 375 376 377 378 379 380 381 382 383 384 385

  bind("create stable t1(ts timestamp, c1 int) TAGS(id int)");
  ASSERT_TRUE(run());

  bind("create stable if not exists test.t1("
       "ts TIMESTAMP, c1 INT, c2 INT UNSIGNED, c3 BIGINT, c4 BIGINT UNSIGNED, c5 FLOAT, c6 DOUBLE, c7 BINARY(20), c8 SMALLINT, "
       "c9 SMALLINT UNSIGNED COMMENT 'test column comment', c10 TINYINT, c11 TINYINT UNSIGNED, c12 BOOL, c13 NCHAR(30), c14 JSON, c15 VARCHAR(50)) "
       "TAGS (tsa TIMESTAMP, a1 INT, a2 INT UNSIGNED, a3 BIGINT, a4 BIGINT UNSIGNED, a5 FLOAT, a6 DOUBLE, a7 BINARY(20), a8 SMALLINT, "
       "a9 SMALLINT UNSIGNED COMMENT 'test column comment', a10 TINYINT, a11 TINYINT UNSIGNED, a12 BOOL, a13 NCHAR(30), a14 JSON, a15 VARCHAR(50)) "
       "KEEP 100 TTL 100 COMMENT 'test create table' SMA(c1, c2, c3)"
      );
  ASSERT_TRUE(run());
386
}