Files
tidb/parser/parser_test.go

394 lines
12 KiB
Go

// Copyright 2015 PingCAP, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// See the License for the specific language governing permissions and
// limitations under the License.
package parser
import (
"fmt"
"testing"
. "github.com/pingcap/check"
"github.com/pingcap/tidb/expression/expressions"
"github.com/pingcap/tidb/stmt/stmts"
)
func TestT(t *testing.T) {
TestingT(t)
}
var _ = Suite(&testParserSuite{})
type testParserSuite struct {
}
// 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},
{"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},
/*{`-- 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 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},
// 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},
// 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},
// 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 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 _, t := range table {
fmt.Printf("%s\n", t.src)
l := NewLexer(t.src)
ok := yyParse(l) == 0
c.Assert(ok, Equals, t.ok, Commentf("source %v", t.src))
switch ok {
case true:
c.Assert(len(l.errs), Equals, 0)
case false:
c.Assert(len(l.errs), Not(Equals), 0)
}
}
// Testcase for unreserved keywords
unreservedKws := []string{
"auto_increment", "after", "begin", "bit", "bool", "boolean", "charset", "columns", "commit",
"date", "datetime", "deallocate", "do", "end", "engine", "engines", "execute", "first", "full",
"local", "names", "offset", "password", "prepare", "quick", "rollback", "session", "signed",
"start", "global", "tables", "text", "time", "timestamp", "transaction", "truncate", "unknown",
"value", "warnings", "year", "now", "substring", "mode", "any", "some", "user", "identified",
}
for _, kw := range unreservedKws {
src := fmt.Sprintf("SELECT %s FROM tbl;", kw)
l := NewLexer(src)
c.Assert(yyParse(l), Equals, 0)
c.Assert(l.errs, HasLen, 0, Commentf("source %s", src))
}
// Testcase for prepared statement
src := "SELECT id+?, id+? from t;"
l := NewLexer(src)
l.SetPrepare()
c.Assert(yyParse(l), Equals, 0)
c.Assert(len(l.ParamList), Equals, 2)
c.Assert(len(l.Stmts()), Equals, 1)
// Testcase for -- Comment and unary -- operator
src = "CREATE TABLE foo (a SMALLINT UNSIGNED, b INT UNSIGNED); -- foo\nSelect --1 from foo;"
l = NewLexer(src)
l.SetPrepare()
c.Assert(yyParse(l), Equals, 0)
c.Assert(len(l.Stmts()), Equals, 2)
// Testcase for CONVERT(expr,type)
src = "SELECT CONVERT('111', SIGNED);"
l = NewLexer(src)
c.Assert(yyParse(l), Equals, 0)
st := l.Stmts()[0]
ss, ok := st.(*stmts.SelectStmt)
c.Assert(ok, IsTrue)
cv, ok := ss.Fields[0].Expr.(*expressions.FunctionCast)
c.Assert(ok, IsTrue)
c.Assert(cv.FunctionType, Equals, expressions.ConvertFunction)
}