diff --git a/parser/coldef/opt.go b/parser/coldef/opt.go index 7fff76a90b..da743eb619 100644 --- a/parser/coldef/opt.go +++ b/parser/coldef/opt.go @@ -221,3 +221,14 @@ func (tc *TableConstraint) String() string { } return strings.Join(tokens, " ") } + +type AuthOption struct { + AuthString string + HashString string + // TODO: support auth_plugin +} + +type UserSpecification struct { + User string + AuthOpt *AuthOption +} diff --git a/parser/parser.y b/parser/parser.y index 57491d3569..75b0b8588a 100644 --- a/parser/parser.y +++ b/parser/parser.y @@ -137,6 +137,7 @@ import ( having "HAVING" highPriority "HIGH_PRIORITY" hour "HOUR" + identified "IDENTIFIED" ignore "IGNORE" ifKwd "IF" ifNull "IFNULL" @@ -217,6 +218,7 @@ import ( unsigned "UNSIGNED" update "UPDATE" use "USE" + user "USER" using "USING" userVar "USER_VAR" value "VALUE" @@ -299,6 +301,7 @@ import ( Assignment "assignment" AssignmentList "assignment list" AssignmentListOpt "assignment list opt" + AuthOption "User auth option" AuthString "Password string value" BeginTransactionStmt "BEGIN TRANSACTION statement" CastType "Cast function target type" @@ -327,6 +330,7 @@ import ( CreateSpecificationList "CREATE Database specification list" CreateSpecListOpt "CREATE Database specification list opt" CreateTableStmt "CREATE TABLE statement" + CreateUserStmt "CREATE User statement" CrossOpt "Cross join option" DBName "Database Name" DeallocateSym "Deallocate or drop" @@ -451,6 +455,8 @@ import ( UnionStmt "Union statement" UpdateStmt "UPDATE statement" Username "Username" + UserSpecification "Username and auth option" + UserSpecificationList "Username and auth option list" UserVariable "User defined variable name" UserVariableList "User defined variable name list" UseStmt "USE statement" @@ -1593,7 +1599,7 @@ UnReservedKeyword: | "DATE" | "DATETIME" | "DEALLOCATE" | "DO" | "END" | "ENGINE" | "ENGINES" | "EXECUTE" | "FIRST" | "FULL" | "LOCAL" | "NAMES" | "OFFSET" | "PASSWORD" %prec lowerThanEq | "PREPARE" | "QUICK" | "ROLLBACK" | "SESSION" | "SIGNED" | "START" | "GLOBAL" | "TABLES"| "TEXT" | "TIME" | "TIMESTAMP" | "TRANSACTION" | "TRUNCATE" | "UNKNOWN" -| "VALUE" | "WARNINGS" | "YEAR" | "MODE" | "WEEK" | "ANY" | "SOME" +| "VALUE" | "WARNINGS" | "YEAR" | "MODE" | "WEEK" | "ANY" | "SOME" | "USER" | "IDENTIFIED" NotKeywordToken: "ABS" | "COALESCE" | "CONCAT" | "CONCAT_WS" | "COUNT" | "DAY" | "DAYOFMONTH" | "DAYOFWEEK" | "DAYOFYEAR" | "FOUND_ROWS" | "GROUP_CONCAT" @@ -3795,5 +3801,43 @@ CommaOpt: { } +/************************************************************************************ + * Account Management Statements + * https://dev.mysql.com/doc/refman/5.7/en/account-management-sql.html + ************************************************************************************/ +CreateUserStmt: + "CREATE" "USER" IfNotExists UserSpecificationList + { + // See: https://dev.mysql.com/doc/refman/5.7/en/create-user.html + + } + +UserSpecification: + Username AuthOption + { + $$ = &coldef.UserSpecification{ + User: $1.(string), + AuthOpt: $2.(*coldef.AuthOption), + } + } + +UserSpecificationList: + UserSpecification + { + $$ = []*coldef.UserSpecification{$1.(*coldef.UserSpecification)} + } +| UserSpecificationList ',' UserSpecification + { + $$ = append($1.([]*coldef.UserSpecification), $3.(*coldef.UserSpecification)) + } + +AuthOption: + {} +| "IDENTIFIED" "BY" AuthString + { + $$ = &coldef.AuthOption { + AuthString: $3.(string), + } + } %% diff --git a/parser/parser_test.go b/parser/parser_test.go index 170f30c75d..b6ee660b2e 100644 --- a/parser/parser_test.go +++ b/parser/parser_test.go @@ -325,6 +325,10 @@ func (s *testParserSuite) TestParser0(c *C) { // For comparison {"select 1 <=> 0, 1 <=> null, 1 = null", true}, + + // For create user + {"CREATE USER 'root'@'localhost' IDENTIFIED BY 'new-password'", true}, + {"CREATE USER 'root'@'localhost' IDENTIFIED BY 'new-password', 'root'@'127.0.0.1' IDENTIFIED BY 'new-password'", true}, } for _, t := range table { diff --git a/parser/scanner.l b/parser/scanner.l index 67731e232e..772b2eef85 100644 --- a/parser/scanner.l +++ b/parser/scanner.l @@ -298,6 +298,7 @@ group_concat {g}{r}{o}{u}{p}_{c}{o}{n}{c}{a}{t} having {h}{a}{v}{i}{n}{g} high_priority {h}{i}{g}{h}_{p}{r}{i}{o}{r}{i}{t}{y} hour {h}{o}{u}{r} +identified {i}{d}{e}{n}{t}{i}{f}{i}{e}{d} if {i}{f} ifnull {i}{f}{n}{u}{l}{l} ignore {i}{g}{n}{o}{r}{e} @@ -431,6 +432,7 @@ duration {d}{u}{r}{a}{t}{i}{o}{n} rune {r}{u}{n}{e} string {s}{t}{r}{i}{n}{g} use {u}{s}{e} +user {u}{s}{e}{r} using {u}{s}{i}{n}{g} idchar0 [a-zA-Z_] @@ -588,6 +590,8 @@ sys_var "@@"(({global}".")|({session}".")|{local}".")?{ident} {high_priority} return highPriority {hour} lval.item = string(l.val) return hour +{identified} lval.item = string(l.val) + return identified {if} lval.item = string(l.val) return ifKwd {ifnull} lval.item = string(l.val) @@ -694,6 +698,8 @@ sys_var "@@"(({global}".")|({session}".")|{local}".")?{ident} return nullIf {update} return update {use} return use +{user} lval.item = string(l.val) + return user {using} return using {value} lval.item = string(l.val) return value