Repository: pingcap/tidb (Go)

Issue:
Inconsistent error with MySQL for GRANT CREATE USER ON <specific db>.*
## Bug Report

Please answer these questions before submitting your issue. Thanks!

### 1. Minimal reproduce step (Required)

create user testuser@localhost;
grant create user on test.* to testuser@localhost;

### 2. What did you expect to see? (Required)

mysql> create user testuser@localhost;
Query OK, 0 rows affected (0.04 sec)

mysql> grant create user on test.* to testuser@localhost;
ERROR 1221 (HY000): Incorrect usage of DB GRANT and GLOBAL PRIVILEGES

### 3. What did you see instead (Required)

tidb> create user testuser@localhost;
Query OK, 0 rows affected (0.01 sec)

tidb> grant create user on test.* to testuser@localhost;
ERROR 1054 (42S22): Unknown column 'Create_user_priv' in 'field list'

### 4. What is your TiDB version? (Required)

tidb_version(): Release Version: v4.0.0-beta.2-2806-ga6ec081b8
Edition: Community
Git Commit Hash: a6ec081b82a5357a9688a98d4d3cca35c87eab75
Git Branch: HEAD
UTC Build Time: 2021-05-06 14:56:18
GoVersion: go1.13.8
Race Enabled: false
TiKV Min Version: v3.0.0-60965b006877ca7234adaced7890d7b029ed1306
Check Table Before Drop: false




Discussion:
/assign
## Please edit this comment or add a new comment to complete the following information

### Not a bug

1. Remove the 'type/bug' label
2. Add notes to indicate why it is not a bug

### Duplicate bug

1. Add the 'type/duplicate' label
2. Add the link to the original bug

### Bug

Note: Make Sure that 'component', and 'severity' labels are added
Example for how to fill out the template: https://github.com/pingcap/tidb/issues/20100

#### 1. Root Cause Analysis (RCA) (optional) 
<!-- Write down the reason why this bug occurs -->

#### 2. Symptom (optional)

<!-- What will the user see when this bug occurs. The error message may be in the terminal, log or monitoring -->

#### 3. All Trigger Conditions (optional)

<!-- All the user scenarios that may trigger this bug -->

#### 4. Workaround (optional)

#### 5. Affected versions

<!--
In the format of [start_version:end_version], multiple version ranges are
accepted. If the bug only affects the unreleased version, please input:
"unreleased". For example:

Notes:
  1. Do not use any white spaces in '[]'.
  2. The range in '[]' is a closed interval
  3. The version format is `v$Major.$Minor.$Patch`, the $Majoy and $Minor
     number in a version range should be the same. [v3.0.1:v3.1.2] is
     invalid because the $Minor number of the version range is different.

Example 1: [v3.0.1:v3.0.5], [v4.0.1:v4.0.5]
Example 2: unreleased
-->

#### 6. Fixed versions

<!--
The first released version that contains this fix in each minor version. If the bug's affected version has been released, the fixed version should be a detailed version number; If the bug doesn't affect any released version, the fixed version can be "master";  

Example 1: v3.0.13, v4.0.5
Example 2: master
-->



Patch:
diff --git a/errors.toml b/errors.toml
index a54913fa1bd2c..926823909f96e 100644
--- a/errors.toml
+++ b/errors.toml
@@ -501,6 +501,11 @@ error = '''
 Deadlock found when trying to get lock; try restarting transaction
 '''
 
+["executor:1221"]
+error = '''
+Incorrect usage of %s and %s
+'''
+
 ["executor:1242"]
 error = '''
 Subquery returns more than 1 row
diff --git a/executor/errors.go b/executor/errors.go
index 7f3345659e4f9..ad8104a96e7ee 100644
--- a/executor/errors.go
+++ b/executor/errors.go
@@ -42,6 +42,7 @@ var (
 	ErrTableaccessDenied             = dbterror.ClassExecutor.NewStd(mysql.ErrTableaccessDenied)
 	ErrBadDB                         = dbterror.ClassExecutor.NewStd(mysql.ErrBadDB)
 	ErrWrongObject                   = dbterror.ClassExecutor.NewStd(mysql.ErrWrongObject)
+	ErrWrongUsage                    = dbterror.ClassExecutor.NewStd(mysql.ErrWrongUsage)
 	ErrRoleNotGranted                = dbterror.ClassPrivilege.NewStd(mysql.ErrRoleNotGranted)
 	ErrDeadlock                      = dbterror.ClassExecutor.NewStd(mysql.ErrLockDeadlock)
 	ErrQueryInterrupted              = dbterror.ClassExecutor.NewStd(mysql.ErrQueryInterrupted)
diff --git a/executor/grant.go b/executor/grant.go
index 6c715758b6c7f..86620cc0124b1 100644
--- a/executor/grant.go
+++ b/executor/grant.go
@@ -473,6 +473,12 @@ func (e *GrantExec) grantDBLevel(priv *ast.PrivElem, user *ast.UserSpec, interna
 	if priv.Priv == mysql.UsagePriv {
 		return nil
 	}
+	for _, v := range mysql.StaticGlobalOnlyPrivs {
+		if v == priv.Priv {
+			return ErrWrongUsage.GenWithStackByArgs("DB GRANT", "GLOBAL PRIVILEGES")
+		}
+	}
+
 	dbName := e.Level.DBName
 	if len(dbName) == 0 {
 		dbName = e.ctx.GetSessionVars().CurrentDB
diff --git a/go.mod b/go.mod
index cd8becf5a757c..b2bd664da13f3 100644
--- a/go.mod
+++ b/go.mod
@@ -47,7 +47,7 @@ require (
 	github.com/pingcap/goleveldb v0.0.0-20191226122134-f82aafb29989
 	github.com/pingcap/kvproto v0.0.0-20210429093846-65f54a202d7e
 	github.com/pingcap/log v0.0.0-20210317133921-96f4fcab92a4
-	github.com/pingcap/parser v0.0.0-20210508071014-cd9cd78e230c
+	github.com/pingcap/parser v0.0.0-20210513020953-ae2c4497c07b
 	github.com/pingcap/sysutil v0.0.0-20210315073920-cc0985d983a3
 	github.com/pingcap/tidb-tools v4.0.9-0.20201127090955-2707c97b3853+incompatible
 	github.com/pingcap/tipb v0.0.0-20210422074242-57dd881b81b1
diff --git a/go.sum b/go.sum
index 4e1030039a04f..c42d129ae5b8b 100644
--- a/go.sum
+++ b/go.sum
@@ -443,8 +443,8 @@ github.com/pingcap/log v0.0.0-20200511115504-543df19646ad/go.mod h1:4rbK1p9ILyIf
 github.com/pingcap/log v0.0.0-20201112100606-8f1e84a3abc8/go.mod h1:4rbK1p9ILyIfb6hU7OG2CiWSqMXnp3JMbiaVJ6mvoY8=
 github.com/pingcap/log v0.0.0-20210317133921-96f4fcab92a4 h1:ERrF0fTuIOnwfGbt71Ji3DKbOEaP189tjym50u8gpC8=
 github.com/pingcap/log v0.0.0-20210317133921-96f4fcab92a4/go.mod h1:4rbK1p9ILyIfb6hU7OG2CiWSqMXnp3JMbiaVJ6mvoY8=
-github.com/pingcap/parser v0.0.0-20210508071014-cd9cd78e230c h1:GLFd+wBN7EsV6ad/tVGFCD37taOyzIMVs3SdiWZF18I=
-github.com/pingcap/parser v0.0.0-20210508071014-cd9cd78e230c/go.mod h1:xZC8I7bug4GJ5KtHhgAikjTfU4kBv1Sbo3Pf1MZ6lVw=
+github.com/pingcap/parser v0.0.0-20210513020953-ae2c4497c07b h1:eLuDQ6eJCEKCbGwhGrkjzagwev1GJGU2Y2kFkAsBzV0=
+github.com/pingcap/parser v0.0.0-20210513020953-ae2c4497c07b/go.mod h1:xZC8I7bug4GJ5KtHhgAikjTfU4kBv1Sbo3Pf1MZ6lVw=
 github.com/pingcap/sysutil v0.0.0-20200206130906-2bfa6dc40bcd/go.mod h1:EB/852NMQ+aRKioCpToQ94Wl7fktV+FNnxf3CX/TTXI=
 github.com/pingcap/sysutil v0.0.0-20210315073920-cc0985d983a3 h1:A9KL9R+lWSVPH8IqUuH1QSTRJ5FGoY1bT2IcfPKsWD8=
 github.com/pingcap/sysutil v0.0.0-20210315073920-cc0985d983a3/go.mod h1:tckvA041UWP+NqYzrJ3fMgC/Hw9wnmQ/tUkp/JaHly8=


Test patch:
diff --git a/executor/grant_test.go b/executor/grant_test.go
index bb720b48b730b..13686494feddc 100644
--- a/executor/grant_test.go
+++ b/executor/grant_test.go
@@ -89,6 +89,10 @@ func (s *testSuite3) TestGrantDBScope(c *C) {
 		sql := fmt.Sprintf("SELECT %s FROM mysql.DB WHERE User=\"testDB1\" and host=\"localhost\" and db=\"test\";", mysql.Priv2UserCol[v])
 		tk.MustQuery(sql).Check(testkit.Rows("Y"))
 	}
+
+	// Grant in wrong scope.
+	_, err := tk.Exec(` grant create user on test.* to 'testDB1'@'localhost';`)
+	c.Assert(terror.ErrorEqual(err, executor.ErrWrongUsage.GenWithStackByArgs("DB GRANT", "GLOBAL PRIVILEGES")), IsTrue)
 }
 
 func (s *testSuite3) TestWithGrantOption(c *C) {