diff --git a/parser/parser_test.go b/parser/parser_test.go index 7b84fe89d9..6e3d0f5751 100644 --- a/parser/parser_test.go +++ b/parser/parser_test.go @@ -49,509 +49,7 @@ func (s *testParserSuite) TestOriginText(c *C) { FROM stuff`) } -// TODO: table 43 and 50 parse failed -func (s *testParserSuite) TestParser0(c *C) { - table := []struct { - src string - ok bool - }{ - {"", true}, - {";", true}, - {"CREATE", false}, - {"CREATE TABLE", false}, - {"CREATE TABLE foo (", false}, - // 5 - {"CREATE TABLE foo ()", false}, - {"CREATE TABLE foo ();", false}, - {"CREATE TABLE foo (a TINYINT UNSIGNED);", true}, - {"CREATE TABLE foo (a SMALLINT UNSIGNED, b INT UNSIGNED)", true}, - // 10 - {"CREATE TABLE foo (a bigint unsigned, b bool);", true}, - {"CREATE TABLE foo (a TINYINT, b SMALLINT) CREATE TABLE bar (x INT, y int64)", false}, - {"CREATE TABLE foo (a int, b float); CREATE TABLE bar (x double, y float)", true}, - {"INSERT INTO foo VALUES (1234)", true}, - {"INSERT INTO foo VALUES (1234, 5678)", true}, - // 15 - {"INSERT INTO foo VALUES (1 || 2)", true}, - {"INSERT INTO foo VALUES (1 | 2)", true}, - {"INSERT INTO foo VALUES (false || true)", true}, - {"INSERT INTO foo VALUES (bar(5678))", false}, - // 20 - {"INSERT INTO foo VALUES ()", true}, - {"CREATE TABLE foo (a.b, b);", false}, - {"CREATE TABLE foo (a, b.c);", false}, - {"SELECT * FROM t", true}, - {"SELECT * FROM t AS u", true}, - // 25 - {"SELECT * FROM t, v", true}, - {"SELECT * FROM t AS u, v", true}, - {"SELECT * FROM t, v AS w", true}, - {"SELECT * FROM t AS u, v AS w", true}, - {"SELECT * FROM foo, bar, foo", true}, - // 30 - {"CREATE TABLE foo (a bytes)", false}, - {"SELECT DISTINCTS * FROM t", false}, - {"SELECT DISTINCT * FROM t", true}, - {"INSERT INTO foo (a) VALUES (42)", true}, - {"INSERT INTO foo (a,) VALUES (42,)", false}, - // 35 - {"INSERT INTO foo (a,b) VALUES (42,314)", true}, - {"INSERT INTO foo (a,b,) VALUES (42,314)", false}, - {"INSERT INTO foo (a,b,) VALUES (42,314,)", false}, - {"INSERT INTO foo () VALUES ()", true}, - {"INSERT INTO foo VALUE ()", true}, - {"CREATE TABLE foo (a SMALLINT UNSIGNED, b INT UNSIGNED)", true}, - {"CREATE TABLE foo (a SMALLINT UNSIGNED, b INT UNSIGNED) -- foo", true}, - // 40 - {"CREATE TABLE foo (a SMALLINT UNSIGNED, b INT UNSIGNED) // foo", true}, - {"CREATE TABLE foo (a SMALLINT UNSIGNED, b INT UNSIGNED) /* foo */", true}, - {"CREATE TABLE foo /* foo */ (a SMALLINT UNSIGNED, b INT UNSIGNED) /* foo */", true}, - {`SELECT stuff.id - FROM stuff - WHERE stuff.value >= ALL (SELECT stuff.value - FROM stuff)`, true}, - /*{`-- Examples - ALTER TABLE Stock ADD Qty int; - - ALTER TABLE Income DROP COLUMN Taxes; - - CREATE TABLE department - ( - DepartmentID int, - DepartmentName string, // optional comma - ); - - CREATE TABLE employee - ( - LastName string, - DepartmentID int // optional comma - ); - - DROP TABLE Inventory; - - INSERT INTO department (DepartmentID) VALUES (42); - - INSERT INTO department ( - DepartmentName, - DepartmentID, - ) - VALUES ( - "R&D", - 42, - ); - - INSERT INTO department VALUES ( - 42, - "R&D", - ); - - SELECT * FROM Stock; - - SELECT DepartmentID - FROM department - WHERE DepartmentID == 42 - ORDER BY DepartmentName; - - SELECT employee.LastName - FROM department, employee - WHERE department.DepartmentID == employee.DepartmentID - ORDER BY DepartmentID; - - SELECT a.b, c.d - FROM - x AS a, - ( - SELECT * FROM y; // optional semicolon - ) AS c - WHERE a.e > c.e; - - SELECT a.b, c.d - FROM - x AS a, - ( - SELECT * FROM y // no semicolon - ) AS c - WHERE a.e > c.e; - - TRUNCATE TABLE department; - - SELECT DepartmentID - FROM department - WHERE DepartmentID == ?1 - ORDER BY DepartmentName; - - SELECT employee.LastName - FROM department, employee - WHERE department.DepartmentID == $1 && employee.LastName > $2 - ORDER BY DepartmentID; - - `, true}, - */ - {"BEGIN", true}, - {"START TRANSACTION", true}, - // 45 - {"COMMIT", true}, - {"ROLLBACK", true}, - {` - BEGIN; - INSERT INTO foo VALUES (42, 3.14); - INSERT INTO foo VALUES (-1, 2.78); - COMMIT;`, true}, - {` // A - BEGIN; - INSERT INTO tmp SELECT * from bar; - SELECT * from tmp; - - // B - ROLLBACK;`, true}, - // 50 - /* - {`-- 6 - ALTER TABLE none DROP COLUMN c1; - `, true}, - */ - - // set - // user defined - {"SET @a = 1", true}, - // session system variables - {"SET SESSION autocommit = 1", true}, - {"SET @@session.autocommit = 1", true}, - {"SET LOCAL autocommit = 1", true}, - {"SET @@local.autocommit = 1", true}, - {"SET @@autocommit = 1", true}, - {"SET autocommit = 1", true}, - // global system variables - {"SET GLOBAL autocommit = 1", true}, - {"SET @@global.autocommit = 1", true}, - // SET CHARACTER SET - {"SET CHARACTER SET utf8mb4;", true}, - {"SET CHARACTER SET 'utf8mb4';", true}, - // Set password - {"SET PASSWORD = 'password';", true}, - {"SET PASSWORD FOR 'root'@'localhost' = 'password';", true}, - - // qualified select - {"SELECT a.b.c FROM t", true}, - {"SELECT a.b.*.c FROM t", false}, - {"SELECT a.b.* FROM t", true}, - {"SELECT a FROM t", true}, - {"SELECT a.b.c.d FROM t", false}, - - // Do statement - {"DO 1", true}, - {"DO 1 from t", false}, - - // Sign expression - {"SELECT ++1", true}, - {"SELECT -*1", false}, - {"SELECT -+1", true}, - {"SELECT -1", true}, - {"SELECT --1", true}, - - // Select for update - {"SELECT * from t for update", true}, - {"SELECT * from t lock in share mode", true}, - - // For alter table - {"ALTER TABLE t ADD COLUMN a SMALLINT UNSIGNED", true}, - {"ALTER TABLE t ADD COLUMN a SMALLINT UNSIGNED FIRST", true}, - {"ALTER TABLE t ADD COLUMN a SMALLINT UNSIGNED AFTER b", true}, - - // from join - {"SELECT * from t1, t2, t3", true}, - {"select * from t1 join t2 left join t3 on t2.id = t3.id", true}, - {"select * from t1 right join t2 on t1.id = t2.id left join t3 on t3.id = t2.id", true}, - {"select * from t1 right join t2 on t1.id = t2.id left join t3", false}, - - // For default value - {"CREATE TABLE sbtest (id INTEGER UNSIGNED NOT NULL AUTO_INCREMENT, k integer UNSIGNED DEFAULT '0' NOT NULL, c char(120) DEFAULT '' NOT NULL, pad char(60) DEFAULT '' NOT NULL, PRIMARY KEY (id) )", true}, - - // For show full columns - {"show columns in t;", true}, - {"show full columns in t;", true}, - - // For set names - {"set names utf8", true}, - {"set names utf8 collate utf8_unicode_ci", true}, - - // For show character set - {"show character set;", true}, - // For on duplicate key update - {"INSERT INTO t (a,b,c) VALUES (1,2,3),(4,5,6) ON DUPLICATE KEY UPDATE c=VALUES(a)+VALUES(b);", true}, - {"INSERT IGNORE INTO t (a,b,c) VALUES (1,2,3),(4,5,6) ON DUPLICATE KEY UPDATE c=VALUES(a)+VALUES(b);", true}, - - // For buildin functions - {"SELECT DAYOFMONTH('2007-02-03');", true}, - {"SELECT RAND();", true}, - {"SELECT RAND(1);", true}, - - {"SELECT SUBSTRING('Quadratically',5);", true}, - {"SELECT SUBSTRING('Quadratically',5, 3);", true}, - {"SELECT SUBSTRING('Quadratically' FROM 5);", true}, - {"SELECT SUBSTRING('Quadratically' FROM 5 FOR 3);", true}, - - {"SELECT CONVERT('111', SIGNED);", true}, - - {"SELECT DATABASE();", true}, - {"SELECT USER();", true}, - {"SELECT CURRENT_USER();", true}, - {"SELECT CURRENT_USER;", true}, - - {"SELECT SUBSTRING_INDEX('www.mysql.com', '.', 2);", true}, - {"SELECT SUBSTRING_INDEX('www.mysql.com', '.', -2);", true}, - - {`SELECT LOWER("A"), UPPER("a")`, true}, - - {`SELECT LOCATE('bar', 'foobarbar');`, true}, - {`SELECT LOCATE('bar', 'foobarbar', 5);`, true}, - - {"select current_date, current_date(), curdate()", true}, - - // For delete statement - {"DELETE t1, t2 FROM t1 INNER JOIN t2 INNER JOIN t3 WHERE t1.id=t2.id AND t2.id=t3.id;", true}, - {"DELETE FROM t1, t2 USING t1 INNER JOIN t2 INNER JOIN t3 WHERE t1.id=t2.id AND t2.id=t3.id;", true}, - {"DELETE t1, t2 FROM t1 INNER JOIN t2 INNER JOIN t3 WHERE t1.id=t2.id AND t2.id=t3.id limit 10;", false}, - - // For time fsp - {"CREATE TABLE t( c1 TIME(2), c2 DATETIME(2), c3 TIMESTAMP(2) );", true}, - - // For row - {"select row(1)", false}, - {"select row(1, 1,)", false}, - {"select (1, 1,)", false}, - {"select row(1, 1) > row(1, 1), row(1, 1, 1) > row(1, 1, 1)", true}, - {"Select (1, 1) > (1, 1)", true}, - {"create table t (row int)", true}, - - // For SHOW statement - {"SHOW VARIABLES LIKE 'character_set_results'", true}, - {"SHOW GLOBAL VARIABLES LIKE 'character_set_results'", true}, - {"SHOW SESSION VARIABLES LIKE 'character_set_results'", true}, - {"SHOW VARIABLES", true}, - {"SHOW GLOBAL VARIABLES", true}, - {"SHOW GLOBAL VARIABLES WHERE Variable_name = 'autocommit'", true}, - {`SHOW FULL TABLES FROM icar_qa LIKE play_evolutions`, true}, - {`SHOW FULL TABLES WHERE Table_Type != 'VIEW'`, true}, - - // For compare subquery - {"SELECT 1 > (select 1)", true}, - {"SELECT 1 > ANY (select 1)", true}, - {"SELECT 1 > ALL (select 1)", true}, - {"SELECT 1 > SOME (select 1)", true}, - - // For exists subquery - {"SELECT EXISTS select 1", false}, - {"SELECT EXISTS (select 1)", true}, - {"SELECT + EXISTS (select 1)", true}, - {"SELECT - EXISTS (select 1)", true}, - {"SELECT NOT EXISTS (select 1)", true}, - {"SELECT + NOT EXISTS (select 1)", false}, - {"SELECT - NOT EXISTS (select 1)", false}, - - // For update statement - {"UPDATE t SET id = id + 1 ORDER BY id DESC;", true}, - {"UPDATE items,month SET items.price=month.price WHERE items.id=month.id;", true}, - {"UPDATE items,month SET items.price=month.price WHERE items.id=month.id LIMIT 10;", false}, - {"UPDATE user T0 LEFT OUTER JOIN user_profile T1 ON T1.id = T0.profile_id SET T0.profile_id = 1 WHERE T0.profile_id IN (1);", true}, - - // For cast with charset - {"SELECT *, CAST(data AS CHAR CHARACTER SET utf8) FROM t;", true}, - - // For binary operator - {"SELECT binary 'a';", true}, - - // For hexadecimal - {"SELECT x'0a', X'11', 0x11", true}, - {"select x'0xaa'", false}, - {"select 0X11", false}, - - // For comparison - {"select 1 <=> 0, 1 <=> null, 1 = null", true}, - - // For bit - {"select 0b01, 0b0, b'11', B'11'", true}, - {"select 0B01", false}, - {"select 0b21", false}, - - // For create user - {`CREATE USER IF NOT EXISTS 'root'@'localhost' IDENTIFIED BY 'new-password'`, true}, - {`CREATE USER 'root'@'localhost' IDENTIFIED BY 'new-password'`, true}, - {`CREATE USER 'root'@'localhost' IDENTIFIED BY PASSWORD 'hashstring'`, true}, - {`CREATE USER 'root'@'localhost' IDENTIFIED BY 'new-password', 'root'@'127.0.0.1' IDENTIFIED BY PASSWORD 'hashstring'`, true}, - - // For select with where clause - {"SELECT * FROM t WHERE 1 = 1", true}, - - // For comment in query - {"/*comment*/ /*comment*/ select c /* this is a comment */ from t;", true}, - - // For show collation - {"show collation", true}, - {"show collation like 'utf8%'", true}, - {"show collation where Charset = 'utf8' and Collation = 'utf8_bin'", true}, - - // For drop datbase/schema - {"create database xxx", true}, - {"create database if exists xxx", false}, - {"create database if not exists xxx", true}, - {"create schema xxx", true}, - {"create schema if exists xxx", false}, - {"create schema if not exists xxx", true}, - {"drop database xxx", true}, - {"drop database if exists xxx", true}, - {"drop database if not exists xxx", false}, - {"drop schema xxx", true}, - {"drop schema if exists xxx", true}, - {"drop schema if not exists xxx", false}, - - // For issue 224 - {`SELECT CAST('test collated returns' AS CHAR CHARACTER SET utf8) COLLATE utf8_bin;`, true}, - - // Select time - {"select current_timestamp", true}, - {"select current_timestamp()", true}, - {"select current_timestamp(6)", true}, - {"select now()", true}, - {"select now(6)", true}, - {"select sysdate(), sysdate(6)", true}, - - // For dual - {"select 1 from dual", true}, - {"select 1 from dual limit 1", true}, - - // For enum and set type - {"create table t (c1 enum('a', 'b'), c2 set('a', 'b'))", true}, - {"create table t (c1 enum)", false}, - {"create table t (c1 set)", false}, - - // For comment - {"create table t (c int comment 'comment')", true}, - {"create table t (c int) comment = 'comment'", true}, - {"create table t (c int) comment 'comment'", true}, - {"create table t (c int) comment comment", false}, - {"create table t (comment text)", true}, - - // For string literal - {`select '''a''', """a"""`, true}, - {`select ''a''`, false}, - {`select ""a""`, false}, - {`select '''a''';`, true}, - {`select '\'a\'';`, true}, - {`select "\"a\"";`, true}, - {`select """a""";`, true}, - - // For table option - {"create table t (c int) avg_row_length = 3", true}, - {"create table t (c int) avg_row_length 3", true}, - {"create table t (c int) checksum = 0", true}, - {"create table t (c int) checksum 1", true}, - {"create table t (c int) compression = none", true}, - {"create table t (c int) compression lz4", true}, - {"create table t (c int) connection = 'abc'", true}, - {"create table t (c int) connection 'abc'", true}, - {"create table t (c int) key_block_size = 1024", true}, - {"create table t (c int) key_block_size 1024", true}, - {"create table t (c int) max_rows = 1000", true}, - {"create table t (c int) max_rows 1000", true}, - {"create table t (c int) min_rows = 1000", true}, - {"create table t (c int) min_rows 1000", true}, - {"create table t (c int) password = 'abc'", true}, - {"create table t (c int) password 'abc'", true}, - - // For show create table - {"show create table test.t", true}, - {"show create table t", true}, - - // For national - {"create table t (c1 national char(2), c2 national varchar(2))", true}, - - // For blob and text field length - {"create table t (c1 blob(1024), c2 text(1024))", true}, - - // For check - {"create table t (c1 bool, c2 bool, check (c1 in (0, 1)), check (c2 in (0, 1)))", true}, - - // For year - {"create table t (y year(4), y1 year)", true}, - - // For quote identifier - {"select `a`, `a.b`, `a b` from t", true}, - - // For union - {"select c1 from t1 union select c2 from t2", true}, - {"select c1 from t1 union (select c2 from t2)", true}, - {"select c1 from t1 union (select c2 from t2) order by c1", true}, - {"select c1 from t1 union select c2 from t2 order by c2", true}, - {"select c1 from t1 union (select c2 from t2) limit 1", true}, - {"select c1 from t1 union (select c2 from t2) limit 1, 1", true}, - {"select c1 from t1 union (select c2 from t2) order by c1 limit 1", true}, - {"(select c1 from t1) union distinct select c2 from t2", true}, - {"(select c1 from t1) union all select c2 from t2", true}, - {"(select c1 from t1) union (select c2 from t2) order by c1 union select c3 from t3", false}, - {"(select c1 from t1) union (select c2 from t2) limit 1 union select c3 from t3", false}, - {"(select c1 from t1) union select c2 from t2 union (select c3 from t3) order by c1 limit 1", true}, - {"select (select 1 union select 1) as a", true}, - {"select * from (select 1 union select 2) as a", true}, - {"insert into t select c1 from t1 union select c2 from t2", true}, - {"insert into t (c) select c1 from t1 union select c2 from t2", true}, - - // For unquoted identifier - {"create table MergeContextTest$Simple (value integer not null, primary key (value))", true}, - - // For check clause - {"CREATE TABLE Customer (SD integer CHECK (SD > 0), First_Name varchar(30));", true}, - - // For time extract - {`select extract(microsecond from "2011-11-11 10:10:10.123456")`, true}, - {`select extract(second from "2011-11-11 10:10:10.123456")`, true}, - {`select extract(minute from "2011-11-11 10:10:10.123456")`, true}, - {`select extract(hour from "2011-11-11 10:10:10.123456")`, true}, - {`select extract(day from "2011-11-11 10:10:10.123456")`, true}, - {`select extract(week from "2011-11-11 10:10:10.123456")`, true}, - {`select extract(month from "2011-11-11 10:10:10.123456")`, true}, - {`select extract(quarter from "2011-11-11 10:10:10.123456")`, true}, - {`select extract(year from "2011-11-11 10:10:10.123456")`, true}, - {`select extract(second_microsecond from "2011-11-11 10:10:10.123456")`, true}, - {`select extract(minute_microsecond from "2011-11-11 10:10:10.123456")`, true}, - {`select extract(minute_second from "2011-11-11 10:10:10.123456")`, true}, - {`select extract(hour_microsecond from "2011-11-11 10:10:10.123456")`, true}, - {`select extract(hour_second from "2011-11-11 10:10:10.123456")`, true}, - {`select extract(hour_minute from "2011-11-11 10:10:10.123456")`, true}, - {`select extract(day_microsecond from "2011-11-11 10:10:10.123456")`, true}, - {`select extract(day_second from "2011-11-11 10:10:10.123456")`, true}, - {`select extract(day_minute from "2011-11-11 10:10:10.123456")`, true}, - {`select extract(day_hour from "2011-11-11 10:10:10.123456")`, true}, - {`select extract(year_month from "2011-11-11 10:10:10.123456")`, true}, - - // For as - {"select 1 as a, 1 as `a`, 1 as \"a\", 1 as 'a'", true}, - {`select 1 as a, 1 as "a", 1 as 'a'`, true}, - {`select 1 a, 1 "a", 1 'a'`, true}, - {`select * from t as "a"`, false}, - {`select * from t a`, true}, - {`select * from t as a`, true}, - {"select 1 full, 1 row, 1 abs", true}, - {"select * from t full, t1 row, t2 abs", true}, - - // For https://github.com/pingcap/tidb/issues/312 - {`create table t (c float(53));`, true}, - {`create table t (c float(54));`, false}, - } - - for _, t := range table { - l := NewLexer(t.src) - ok := yyParse(l) == 0 - c.Assert(ok, Equals, t.ok, Commentf("source %v %v", t.src, l.errs)) - - switch ok { - case true: - c.Assert(l.errs, HasLen, 0, Commentf("src: %s", t.src)) - case false: - c.Assert(len(l.errs), Not(Equals), 0, Commentf("src: %s", t.src)) - } - } - +func (s *testParserSuite) TestSimple(c *C) { // Testcase for unreserved keywords unreservedKws := []string{ "auto_increment", "after", "begin", "bit", "bool", "boolean", "charset", "columns", "commit", @@ -611,3 +109,458 @@ func (s *testParserSuite) TestParser0(c *C) { c.Assert(ok, IsTrue) } } + +type testCase struct { + src string + ok bool +} + +func (s *testParserSuite) RunTest(c *C, table []testCase) { + for _, t := range table { + l := NewLexer(t.src) + ok := yyParse(l) == 0 + c.Assert(ok, Equals, t.ok, Commentf("source %v %v", t.src, l.errs)) + switch ok { + case true: + c.Assert(l.errs, HasLen, 0, Commentf("src: %s", t.src)) + case false: + c.Assert(len(l.errs), Not(Equals), 0, Commentf("src: %s", t.src)) + } + } +} +func (s *testParserSuite) TestDMLStmt(c *C) { + table := []testCase{ + {"", true}, + {";", true}, + {"INSERT INTO foo VALUES (1234)", true}, + {"INSERT INTO foo VALUES (1234, 5678)", true}, + // 15 + {"INSERT INTO foo VALUES (1 || 2)", true}, + {"INSERT INTO foo VALUES (1 | 2)", true}, + {"INSERT INTO foo VALUES (false || true)", true}, + {"INSERT INTO foo VALUES (bar(5678))", false}, + // 20 + {"INSERT INTO foo VALUES ()", true}, + {"SELECT * FROM t", true}, + {"SELECT * FROM t AS u", true}, + // 25 + {"SELECT * FROM t, v", true}, + {"SELECT * FROM t AS u, v", true}, + {"SELECT * FROM t, v AS w", true}, + {"SELECT * FROM t AS u, v AS w", true}, + {"SELECT * FROM foo, bar, foo", true}, + // 30 + {"SELECT DISTINCTS * FROM t", false}, + {"SELECT DISTINCT * FROM t", true}, + {"INSERT INTO foo (a) VALUES (42)", true}, + {"INSERT INTO foo (a,) VALUES (42,)", false}, + // 35 + {"INSERT INTO foo (a,b) VALUES (42,314)", true}, + {"INSERT INTO foo (a,b,) VALUES (42,314)", false}, + {"INSERT INTO foo (a,b,) VALUES (42,314,)", false}, + {"INSERT INTO foo () VALUES ()", true}, + {"INSERT INTO foo VALUE ()", true}, + // 40 + {`SELECT stuff.id + FROM stuff + WHERE stuff.value >= ALL (SELECT stuff.value + FROM stuff)`, true}, + {"BEGIN", true}, + {"START TRANSACTION", true}, + // 45 + {"COMMIT", true}, + {"ROLLBACK", true}, + {` + BEGIN; + INSERT INTO foo VALUES (42, 3.14); + INSERT INTO foo VALUES (-1, 2.78); + COMMIT;`, true}, + {` // A + BEGIN; + INSERT INTO tmp SELECT * from bar; + SELECT * from tmp; + + // B + ROLLBACK;`, true}, + + // set + // user defined + {"SET @a = 1", true}, + // session system variables + {"SET SESSION autocommit = 1", true}, + {"SET @@session.autocommit = 1", true}, + {"SET LOCAL autocommit = 1", true}, + {"SET @@local.autocommit = 1", true}, + {"SET @@autocommit = 1", true}, + {"SET autocommit = 1", true}, + // global system variables + {"SET GLOBAL autocommit = 1", true}, + {"SET @@global.autocommit = 1", true}, + // SET CHARACTER SET + {"SET CHARACTER SET utf8mb4;", true}, + {"SET CHARACTER SET 'utf8mb4';", true}, + // Set password + {"SET PASSWORD = 'password';", true}, + {"SET PASSWORD FOR 'root'@'localhost' = 'password';", true}, + + // qualified select + {"SELECT a.b.c FROM t", true}, + {"SELECT a.b.*.c FROM t", false}, + {"SELECT a.b.* FROM t", true}, + {"SELECT a FROM t", true}, + {"SELECT a.b.c.d FROM t", false}, + + // Do statement + {"DO 1", true}, + {"DO 1 from t", false}, + + // Select for update + {"SELECT * from t for update", true}, + {"SELECT * from t lock in share mode", true}, + + // For alter table + {"ALTER TABLE t ADD COLUMN a SMALLINT UNSIGNED", true}, + {"ALTER TABLE t ADD COLUMN a SMALLINT UNSIGNED FIRST", true}, + {"ALTER TABLE t ADD COLUMN a SMALLINT UNSIGNED AFTER b", true}, + + // from join + {"SELECT * from t1, t2, t3", true}, + {"select * from t1 join t2 left join t3 on t2.id = t3.id", true}, + {"select * from t1 right join t2 on t1.id = t2.id left join t3 on t3.id = t2.id", true}, + {"select * from t1 right join t2 on t1.id = t2.id left join t3", false}, + + // For show full columns + {"show columns in t;", true}, + {"show full columns in t;", true}, + + // For set names + {"set names utf8", true}, + {"set names utf8 collate utf8_unicode_ci", true}, + + // For show character set + {"show character set;", true}, + // For on duplicate key update + {"INSERT INTO t (a,b,c) VALUES (1,2,3),(4,5,6) ON DUPLICATE KEY UPDATE c=VALUES(a)+VALUES(b);", true}, + {"INSERT IGNORE INTO t (a,b,c) VALUES (1,2,3),(4,5,6) ON DUPLICATE KEY UPDATE c=VALUES(a)+VALUES(b);", true}, + + // For SHOW statement + {"SHOW VARIABLES LIKE 'character_set_results'", true}, + {"SHOW GLOBAL VARIABLES LIKE 'character_set_results'", true}, + {"SHOW SESSION VARIABLES LIKE 'character_set_results'", true}, + {"SHOW VARIABLES", true}, + {"SHOW GLOBAL VARIABLES", true}, + {"SHOW GLOBAL VARIABLES WHERE Variable_name = 'autocommit'", true}, + {`SHOW FULL TABLES FROM icar_qa LIKE play_evolutions`, true}, + {`SHOW FULL TABLES WHERE Table_Type != 'VIEW'`, true}, + + // For default value + {"CREATE TABLE sbtest (id INTEGER UNSIGNED NOT NULL AUTO_INCREMENT, k integer UNSIGNED DEFAULT '0' NOT NULL, c char(120) DEFAULT '' NOT NULL, pad char(60) DEFAULT '' NOT NULL, PRIMARY KEY (id) )", true}, + + // For delete statement + {"DELETE t1, t2 FROM t1 INNER JOIN t2 INNER JOIN t3 WHERE t1.id=t2.id AND t2.id=t3.id;", true}, + {"DELETE FROM t1, t2 USING t1 INNER JOIN t2 INNER JOIN t3 WHERE t1.id=t2.id AND t2.id=t3.id;", true}, + {"DELETE t1, t2 FROM t1 INNER JOIN t2 INNER JOIN t3 WHERE t1.id=t2.id AND t2.id=t3.id limit 10;", false}, + + // For update statement + {"UPDATE t SET id = id + 1 ORDER BY id DESC;", true}, + {"UPDATE items,month SET items.price=month.price WHERE items.id=month.id;", true}, + {"UPDATE items,month SET items.price=month.price WHERE items.id=month.id LIMIT 10;", false}, + {"UPDATE user T0 LEFT OUTER JOIN user_profile T1 ON T1.id = T0.profile_id SET T0.profile_id = 1 WHERE T0.profile_id IN (1);", true}, + + // For select with where clause + {"SELECT * FROM t WHERE 1 = 1", true}, + + // For show collation + {"show collation", true}, + {"show collation like 'utf8%'", true}, + {"show collation where Charset = 'utf8' and Collation = 'utf8_bin'", true}, + + // For dual + {"select 1 from dual", true}, + {"select 1 from dual limit 1", true}, + + // For show create table + {"show create table test.t", true}, + {"show create table t", true}, + } + s.RunTest(c, table) +} + +func (s *testParserSuite) TestExpression(c *C) { + table := []testCase{ + // Sign expression + {"SELECT ++1", true}, + {"SELECT -*1", false}, + {"SELECT -+1", true}, + {"SELECT -1", true}, + {"SELECT --1", true}, + + // For string literal + {`select '''a''', """a"""`, true}, + {`select ''a''`, false}, + {`select ""a""`, false}, + {`select '''a''';`, true}, + {`select '\'a\'';`, true}, + {`select "\"a\"";`, true}, + {`select """a""";`, true}, + // For comparison + {"select 1 <=> 0, 1 <=> null, 1 = null", true}, + } + s.RunTest(c, table) +} + +func (s *testParserSuite) TestBuiltin(c *C) { + table := []testCase{ + // For buildin functions + {"SELECT DAYOFMONTH('2007-02-03');", true}, + {"SELECT RAND();", true}, + {"SELECT RAND(1);", true}, + + {"SELECT SUBSTRING('Quadratically',5);", true}, + {"SELECT SUBSTRING('Quadratically',5, 3);", true}, + {"SELECT SUBSTRING('Quadratically' FROM 5);", true}, + {"SELECT SUBSTRING('Quadratically' FROM 5 FOR 3);", true}, + + {"SELECT CONVERT('111', SIGNED);", true}, + + {"SELECT DATABASE();", true}, + {"SELECT USER();", true}, + {"SELECT CURRENT_USER();", true}, + {"SELECT CURRENT_USER;", true}, + + {"SELECT SUBSTRING_INDEX('www.mysql.com', '.', 2);", true}, + {"SELECT SUBSTRING_INDEX('www.mysql.com', '.', -2);", true}, + + {`SELECT LOWER("A"), UPPER("a")`, true}, + + {`SELECT LOCATE('bar', 'foobarbar');`, true}, + {`SELECT LOCATE('bar', 'foobarbar', 5);`, true}, + + {"select current_date, current_date(), curdate()", true}, + + // For row + {"select row(1)", false}, + {"select row(1, 1,)", false}, + {"select (1, 1,)", false}, + {"select row(1, 1) > row(1, 1), row(1, 1, 1) > row(1, 1, 1)", true}, + {"Select (1, 1) > (1, 1)", true}, + {"create table t (row int)", true}, + + // For cast with charset + {"SELECT *, CAST(data AS CHAR CHARACTER SET utf8) FROM t;", true}, + + // For binary operator + {"SELECT binary 'a';", true}, + + // Select time + {"select current_timestamp", true}, + {"select current_timestamp()", true}, + {"select current_timestamp(6)", true}, + {"select now()", true}, + {"select now(6)", true}, + {"select sysdate(), sysdate(6)", true}, + + // For time extract + {`select extract(microsecond from "2011-11-11 10:10:10.123456")`, true}, + {`select extract(second from "2011-11-11 10:10:10.123456")`, true}, + {`select extract(minute from "2011-11-11 10:10:10.123456")`, true}, + {`select extract(hour from "2011-11-11 10:10:10.123456")`, true}, + {`select extract(day from "2011-11-11 10:10:10.123456")`, true}, + {`select extract(week from "2011-11-11 10:10:10.123456")`, true}, + {`select extract(month from "2011-11-11 10:10:10.123456")`, true}, + {`select extract(quarter from "2011-11-11 10:10:10.123456")`, true}, + {`select extract(year from "2011-11-11 10:10:10.123456")`, true}, + {`select extract(second_microsecond from "2011-11-11 10:10:10.123456")`, true}, + {`select extract(minute_microsecond from "2011-11-11 10:10:10.123456")`, true}, + {`select extract(minute_second from "2011-11-11 10:10:10.123456")`, true}, + {`select extract(hour_microsecond from "2011-11-11 10:10:10.123456")`, true}, + {`select extract(hour_second from "2011-11-11 10:10:10.123456")`, true}, + {`select extract(hour_minute from "2011-11-11 10:10:10.123456")`, true}, + {`select extract(day_microsecond from "2011-11-11 10:10:10.123456")`, true}, + {`select extract(day_second from "2011-11-11 10:10:10.123456")`, true}, + {`select extract(day_minute from "2011-11-11 10:10:10.123456")`, true}, + {`select extract(day_hour from "2011-11-11 10:10:10.123456")`, true}, + {`select extract(year_month from "2011-11-11 10:10:10.123456")`, true}, + + // For issue 224 + {`SELECT CAST('test collated returns' AS CHAR CHARACTER SET utf8) COLLATE utf8_bin;`, true}, + } + s.RunTest(c, table) +} + +func (s *testParserSuite) TestIdentifier(c *C) { + table := []testCase{ + // For quote identifier + {"select `a`, `a.b`, `a b` from t", true}, + // For unquoted identifier + {"create table MergeContextTest$Simple (value integer not null, primary key (value))", true}, + // For as + {"select 1 as a, 1 as `a`, 1 as \"a\", 1 as 'a'", true}, + {`select 1 as a, 1 as "a", 1 as 'a'`, true}, + {`select 1 a, 1 "a", 1 'a'`, true}, + {`select * from t as "a"`, false}, + {`select * from t a`, true}, + {`select * from t as a`, true}, + {"select 1 full, 1 row, 1 abs", true}, + {"select * from t full, t1 row, t2 abs", true}, + } + s.RunTest(c, table) +} + +func (s *testParserSuite) TestDDL(c *C) { + table := []testCase{ + {"CREATE", false}, + {"CREATE TABLE", false}, + {"CREATE TABLE foo (", false}, + {"CREATE TABLE foo ()", false}, + {"CREATE TABLE foo ();", false}, + {"CREATE TABLE foo (a TINYINT UNSIGNED);", true}, + {"CREATE TABLE foo (a SMALLINT UNSIGNED, b INT UNSIGNED)", true}, + {"CREATE TABLE foo (a bigint unsigned, b bool);", true}, + {"CREATE TABLE foo (a TINYINT, b SMALLINT) CREATE TABLE bar (x INT, y int64)", false}, + {"CREATE TABLE foo (a int, b float); CREATE TABLE bar (x double, y float)", true}, + {"CREATE TABLE foo (a bytes)", false}, + {"CREATE TABLE foo (a SMALLINT UNSIGNED, b INT UNSIGNED)", true}, + {"CREATE TABLE foo (a SMALLINT UNSIGNED, b INT UNSIGNED) -- foo", true}, + {"CREATE TABLE foo (a SMALLINT UNSIGNED, b INT UNSIGNED) // foo", true}, + {"CREATE TABLE foo (a SMALLINT UNSIGNED, b INT UNSIGNED) /* foo */", true}, + {"CREATE TABLE foo /* foo */ (a SMALLINT UNSIGNED, b INT UNSIGNED) /* foo */", true}, + {"CREATE TABLE foo (a.b, b);", false}, + {"CREATE TABLE foo (a, b.c);", false}, + // For table option + {"create table t (c int) avg_row_length = 3", true}, + {"create table t (c int) avg_row_length 3", true}, + {"create table t (c int) checksum = 0", true}, + {"create table t (c int) checksum 1", true}, + {"create table t (c int) compression = none", true}, + {"create table t (c int) compression lz4", true}, + {"create table t (c int) connection = 'abc'", true}, + {"create table t (c int) connection 'abc'", true}, + {"create table t (c int) key_block_size = 1024", true}, + {"create table t (c int) key_block_size 1024", true}, + {"create table t (c int) max_rows = 1000", true}, + {"create table t (c int) max_rows 1000", true}, + {"create table t (c int) min_rows = 1000", true}, + {"create table t (c int) min_rows 1000", true}, + {"create table t (c int) password = 'abc'", true}, + {"create table t (c int) password 'abc'", true}, + // For check clause + {"create table t (c1 bool, c2 bool, check (c1 in (0, 1)), check (c2 in (0, 1)))", true}, + {"CREATE TABLE Customer (SD integer CHECK (SD > 0), First_Name varchar(30));", true}, + + {"create database xxx", true}, + {"create database if exists xxx", false}, + {"create database if not exists xxx", true}, + {"create schema xxx", true}, + {"create schema if exists xxx", false}, + {"create schema if not exists xxx", true}, + // For drop datbase/schema + {"drop database xxx", true}, + {"drop database if exists xxx", true}, + {"drop database if not exists xxx", false}, + {"drop schema xxx", true}, + {"drop schema if exists xxx", true}, + {"drop schema if not exists xxx", false}, + } + s.RunTest(c, table) +} + +func (s *testParserSuite) TestType(c *C) { + table := []testCase{ + // For time fsp + {"CREATE TABLE t( c1 TIME(2), c2 DATETIME(2), c3 TIMESTAMP(2) );", true}, + + // For hexadecimal + {"SELECT x'0a', X'11', 0x11", true}, + {"select x'0xaa'", false}, + {"select 0X11", false}, + + // For bit + {"select 0b01, 0b0, b'11', B'11'", true}, + {"select 0B01", false}, + {"select 0b21", false}, + + // For enum and set type + {"create table t (c1 enum('a', 'b'), c2 set('a', 'b'))", true}, + {"create table t (c1 enum)", false}, + {"create table t (c1 set)", false}, + + // For blob and text field length + {"create table t (c1 blob(1024), c2 text(1024))", true}, + + // For year + {"create table t (y year(4), y1 year)", true}, + + // For national + {"create table t (c1 national char(2), c2 national varchar(2))", true}, + + // For https://github.com/pingcap/tidb/issues/312 + {`create table t (c float(53));`, true}, + {`create table t (c float(54));`, false}, + } + s.RunTest(c, table) +} + +func (s *testParserSuite) TestPrivilege(c *C) { + table := []testCase{ + // For create user + {`CREATE USER IF NOT EXISTS 'root'@'localhost' IDENTIFIED BY 'new-password'`, true}, + {`CREATE USER 'root'@'localhost' IDENTIFIED BY 'new-password'`, true}, + {`CREATE USER 'root'@'localhost' IDENTIFIED BY PASSWORD 'hashstring'`, true}, + {`CREATE USER 'root'@'localhost' IDENTIFIED BY 'new-password', 'root'@'127.0.0.1' IDENTIFIED BY PASSWORD 'hashstring'`, true}, + } + s.RunTest(c, table) +} + +func (s *testParserSuite) TestComment(c *C) { + table := []testCase{ + {"create table t (c int comment 'comment')", true}, + {"create table t (c int) comment = 'comment'", true}, + {"create table t (c int) comment 'comment'", true}, + {"create table t (c int) comment comment", false}, + {"create table t (comment text)", true}, + // For comment in query + {"/*comment*/ /*comment*/ select c /* this is a comment */ from t;", true}, + } + s.RunTest(c, table) +} +func (s *testParserSuite) TestSubquery(c *C) { + table := []testCase{ + // For compare subquery + {"SELECT 1 > (select 1)", true}, + {"SELECT 1 > ANY (select 1)", true}, + {"SELECT 1 > ALL (select 1)", true}, + {"SELECT 1 > SOME (select 1)", true}, + + // For exists subquery + {"SELECT EXISTS select 1", false}, + {"SELECT EXISTS (select 1)", true}, + {"SELECT + EXISTS (select 1)", true}, + {"SELECT - EXISTS (select 1)", true}, + {"SELECT NOT EXISTS (select 1)", true}, + {"SELECT + NOT EXISTS (select 1)", false}, + {"SELECT - NOT EXISTS (select 1)", false}, + } + s.RunTest(c, table) +} +func (s *testParserSuite) TestUnion(c *C) { + table := []testCase{ + {"select c1 from t1 union select c2 from t2", true}, + {"select c1 from t1 union (select c2 from t2)", true}, + {"select c1 from t1 union (select c2 from t2) order by c1", true}, + {"select c1 from t1 union select c2 from t2 order by c2", true}, + {"select c1 from t1 union (select c2 from t2) limit 1", true}, + {"select c1 from t1 union (select c2 from t2) limit 1, 1", true}, + {"select c1 from t1 union (select c2 from t2) order by c1 limit 1", true}, + {"(select c1 from t1) union distinct select c2 from t2", true}, + {"(select c1 from t1) union all select c2 from t2", true}, + {"(select c1 from t1) union (select c2 from t2) order by c1 union select c3 from t3", false}, + {"(select c1 from t1) union (select c2 from t2) limit 1 union select c3 from t3", false}, + {"(select c1 from t1) union select c2 from t2 union (select c3 from t3) order by c1 limit 1", true}, + {"select (select 1 union select 1) as a", true}, + {"select * from (select 1 union select 2) as a", true}, + {"insert into t select c1 from t1 union select c2 from t2", true}, + {"insert into t (c) select c1 from t1 union select c2 from t2", true}, + } + s.RunTest(c, table) +}