From 4e3b9bafe9ceef7f333a0f0abdd2beadc2dbe02e Mon Sep 17 00:00:00 2001 From: Shen Li Date: Sun, 11 Oct 2015 15:21:43 +0800 Subject: [PATCH 1/3] *: SubSelect can be used as select statement Fix https://github.com/pingcap/tidb/issues/320 --- parser/parser.y | 5 +++++ parser/parser_test.go | 3 +++ tidb.go | 8 ++++++++ tidb_test.go | 1 + 4 files changed, 17 insertions(+) diff --git a/parser/parser.y b/parser/parser.y index 41cbc0bf427a5..8122bd29df2da 100644 --- a/parser/parser.y +++ b/parser/parser.y @@ -3437,6 +3437,11 @@ Statement: | UnionStmt | UpdateStmt | UseStmt +| SubSelect + { + // `(select 1)`; is a valid select statement + $$ = $1.(*subquery.SubQuery).Stmt + } ExplainableStmt: SelectStmt diff --git a/parser/parser_test.go b/parser/parser_test.go index 0a7abcbf1f3db..26b41030eb8b7 100644 --- a/parser/parser_test.go +++ b/parser/parser_test.go @@ -533,6 +533,9 @@ func (s *testParserSuite) TestParser0(c *C) { {`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/320 + {`(select 1);`, true}, } for _, t := range table { diff --git a/tidb.go b/tidb.go index b9e8f7555baaf..881b564f8dffe 100644 --- a/tidb.go +++ b/tidb.go @@ -257,6 +257,14 @@ func trimSQL(sql string) string { } break } + // Trim leading '('. For `(select 1);` is also a query. + for { + s := strings.TrimPrefix(sql, "(") + if len(s) == len(sql) { + break + } + sql = s + } return sql } diff --git a/tidb_test.go b/tidb_test.go index e076f78ea6ede..ce755993e9cd4 100644 --- a/tidb_test.go +++ b/tidb_test.go @@ -300,6 +300,7 @@ func (s *testMainSuite) TestIsQuery(c *C) { {"/*comment*/ select 1;", true}, {"/*comment*/ /*comment*/ select 1;", true}, {"select /*comment*/ 1 /*comment*/;", true}, + {"(select /*comment*/ 1 /*comment*/);", true}, } for _, t := range tbl { c.Assert(IsQuery(t.sql), Equals, t.ok, Commentf(t.sql)) From abe94aa2baf3cf5be5d080217dd54633335a0526 Mon Sep 17 00:00:00 2001 From: shenli Date: Mon, 12 Oct 2015 13:35:01 +0800 Subject: [PATCH 2/3] parser: Solve merge problem --- parser/parser_test.go | 110 ------------------------------------------ 1 file changed, 110 deletions(-) diff --git a/parser/parser_test.go b/parser/parser_test.go index 6ada6da59078c..88cc15af29cb4 100644 --- a/parser/parser_test.go +++ b/parser/parser_test.go @@ -564,116 +564,6 @@ func (s *testParserSuite) TestUnion(c *C) { {"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 _, 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)) - } - } - - // 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", - "collation", "comment", "avg_row_length", "checksum", "compression", "connection", "key_block_size", - "max_rows", "min_rows", "national", "row", "quarter", - } - 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.(*expression.FunctionCast) - c.Assert(ok, IsTrue) - c.Assert(cv.FunctionType, Equals, expression.ConvertFunction) - - // For query start with comment - srcs := []string{ - "/* some comments */ SELECT CONVERT('111', SIGNED) ;", - "/* some comments */ /*comment*/ SELECT CONVERT('111', SIGNED) ;", - "SELECT /*comment*/ CONVERT('111', SIGNED) ;", - "SELECT CONVERT('111', /*comment*/ SIGNED) ;", - "SELECT CONVERT('111', SIGNED) /*comment*/;", - } - for _, src := range srcs { - l = NewLexer(src) - c.Assert(yyParse(l), Equals, 0) - st = l.Stmts()[0] - ss, ok = st.(*stmts.SelectStmt) - c.Assert(ok, IsTrue) } s.RunTest(c, table) } From 522aa0c85a34cec32f485a7225287a0c275fdfa2 Mon Sep 17 00:00:00 2001 From: shenli Date: Tue, 13 Oct 2015 10:29:56 +0800 Subject: [PATCH 3/3] tidb: Address comment --- tidb.go | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/tidb.go b/tidb.go index 881b564f8dffe..f78a8bbcd0048 100644 --- a/tidb.go +++ b/tidb.go @@ -258,14 +258,7 @@ func trimSQL(sql string) string { break } // Trim leading '('. For `(select 1);` is also a query. - for { - s := strings.TrimPrefix(sql, "(") - if len(s) == len(sql) { - break - } - sql = s - } - return sql + return strings.TrimLeft(sql, "( ") } // IsQuery checks if a sql statement is a query statement.