diff --git a/parser/lexer.go b/parser/lexer.go index c693cc753c..5f1e3cb3d4 100644 --- a/parser/lexer.go +++ b/parser/lexer.go @@ -157,7 +157,7 @@ func (s *Scanner) Lex(v *yySymType) int { return toHex(s, v, lit) case bitLit: return toBit(s, v, lit) - case userVar, sysVar, cast, curDate, extract: + case singleAtIdentifier, doubleAtIdentifier, cast, curDate, extract: v.item = lit return tok case null: @@ -387,7 +387,7 @@ func startWithAt(s *Scanner) (tok int, pos Pos, lit string) { ch1 := s.r.peek() if isIdentFirstChar(ch1) { s.r.incAsLongAs(isIdentChar) - tok, lit = userVar, s.r.data(&pos) + tok, lit = singleAtIdentifier, s.r.data(&pos) } else if ch1 == '@' { s.r.inc() stream := s.r.s[pos.Offset+2:] @@ -401,7 +401,7 @@ func startWithAt(s *Scanner) (tok int, pos Pos, lit string) { } } s.r.incAsLongAs(isIdentChar) - tok, lit = sysVar, s.r.data(&pos) + tok, lit = doubleAtIdentifier, s.r.data(&pos) } else { tok = at } diff --git a/parser/lexer_test.go b/parser/lexer_test.go index 03e106a062..72abf4560b 100644 --- a/parser/lexer_test.go +++ b/parser/lexer_test.go @@ -66,15 +66,15 @@ func (s *testLexerSuite) TestSingleCharOther(c *C) { runTest(c, table) } -func (s *testLexerSuite) TestSysOrUserVar(c *C) { +func (s *testLexerSuite) TestAtLeadingIdentifier(c *C) { defer testleak.AfterTest(c)() table := []testCaseItem{ - {"@a_3cbbc", userVar}, + {"@a_3cbbc", singleAtIdentifier}, {"@-3cbbc", at}, - {"@@global.test", sysVar}, - {"@@session.test", sysVar}, - {"@@local.test", sysVar}, - {"@@test", sysVar}, + {"@@global.test", doubleAtIdentifier}, + {"@@session.test", doubleAtIdentifier}, + {"@@local.test", doubleAtIdentifier}, + {"@@test", doubleAtIdentifier}, } runTest(c, table) } diff --git a/parser/parser.y b/parser/parser.y index 5e33615b56..bf9b548930 100644 --- a/parser/parser.y +++ b/parser/parser.y @@ -47,6 +47,8 @@ import ( %token /*yy:token "%c" */ identifier "identifier" /*yy:token "\"%c\"" */ stringLit "string literal" + singleAtIdentifier "identifier with single leading at" + doubleAtIdentifier "identifier with double leading at" invalid "a special token never used by parser, used by lexer to indicate error" hintBegin "hintBegin is a virtual token for optimizer hint grammar" hintEnd "hintEnd is a virtual token for optimizer hint grammar" @@ -557,8 +559,6 @@ import ( nulleq "<=>" placeholder "PLACEHOLDER" rsh ">>" - sysVar "SYS_VAR" - userVar "USER_VAR" %type AdminStmt "Check table statement or show ddl statement" @@ -1914,9 +1914,9 @@ NUM: intLit Expression: - "USER_VAR" assignmentEq Expression %prec assignmentEq + singleAtIdentifier assignmentEq Expression %prec assignmentEq { - v := $1.(string) + v := $1 v = strings.TrimPrefix(v, "@") $$ = &ast.VariableExpr{ Name: v, @@ -1988,9 +1988,9 @@ Factor: { $$ = &ast.BinaryOperationExpr{Op: $2.(opcode.Op), L: $1.(ast.ExprNode), R: $3.(ast.ExprNode)} } -| Factor CompareOp "USER_VAR" assignmentEq PredicateExpr %prec assignmentEq +| Factor CompareOp singleAtIdentifier assignmentEq PredicateExpr %prec assignmentEq { - v := $3.(string) + v := $3 v = strings.TrimPrefix(v, "@") variable := &ast.VariableExpr{ Name: v, @@ -4927,9 +4927,9 @@ VariableAssignment: { $$ = &ast.VariableAssignment{Name: $2, Value: $4.(ast.ExprNode), IsSystem: true} } -| "SYS_VAR" eq SetExpr +| doubleAtIdentifier eq SetExpr { - v := strings.ToLower($1.(string)) + v := strings.ToLower($1) var isGlobal bool if strings.HasPrefix(v, "@@global.") { isGlobal = true @@ -4943,15 +4943,15 @@ VariableAssignment: } $$ = &ast.VariableAssignment{Name: v, Value: $3.(ast.ExprNode), IsGlobal: isGlobal, IsSystem: true} } -| "USER_VAR" eq Expression +| singleAtIdentifier eq Expression { - v := $1.(string) + v := $1 v = strings.TrimPrefix(v, "@") $$ = &ast.VariableAssignment{Name: v, Value: $3.(ast.ExprNode)} } -| "USER_VAR" assignmentEq Expression +| singleAtIdentifier assignmentEq Expression { - v := $1.(string) + v := $1 v = strings.TrimPrefix(v, "@") $$ = &ast.VariableAssignment{Name: v, Value: $3.(ast.ExprNode)} } @@ -5005,9 +5005,9 @@ Variable: SystemVariable | UserVariable SystemVariable: - "SYS_VAR" + doubleAtIdentifier { - v := strings.ToLower($1.(string)) + v := strings.ToLower($1) var isGlobal bool if strings.HasPrefix(v, "@@global.") { isGlobal = true @@ -5023,21 +5023,25 @@ SystemVariable: } UserVariable: - "USER_VAR" + singleAtIdentifier { - v := $1.(string) + v := $1 v = strings.TrimPrefix(v, "@") $$ = &ast.VariableExpr{Name: v, IsGlobal: false, IsSystem: false} } Username: - stringLit + StringName { - $$ = $1 + "@%" + $$ = $1.(string) + "@%" } -| stringLit "AT" stringLit +| StringName "AT" StringName { - $$ = $1 + "@" + $3 + $$ = $1.(string) + "@" + $3.(string) + } +| StringName singleAtIdentifier + { + $$ = $1.(string) + $2 } UsernameList: diff --git a/parser/parser_test.go b/parser/parser_test.go index cf5cbc28cc..59ee262b36 100644 --- a/parser/parser_test.go +++ b/parser/parser_test.go @@ -1412,6 +1412,24 @@ func (s *testParserSuite) TestPrivilege(c *C) { table := []testCase{ // for create user {`CREATE USER 'test'`, true}, + {`CREATE USER test`, true}, + {"CREATE USER `test`", true}, + {"CREATE USER test-user", false}, + {"CREATE USER test.user", false}, + {"CREATE USER 'test-user'", true}, + {"CREATE USER `test-user`", true}, + {"CREATE USER test.user", false}, + {"CREATE USER 'test.user'", true}, + {"CREATE USER `test.user`", true}, + {"CREATE USER uesr1@localhost", true}, + {"CREATE USER `uesr1`@localhost", true}, + {"CREATE USER uesr1@`localhost`", true}, + {"CREATE USER `uesr1`@`localhost`", true}, + {"CREATE USER 'uesr1'@localhost", true}, + {"CREATE USER uesr1@'localhost'", true}, + {"CREATE USER 'uesr1'@'localhost'", true}, + {"CREATE USER 'uesr1'@`localhost`", true}, + {"CREATE USER `uesr1`@'localhost'", true}, {`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},