forked from Shiloh/githaven
521 lines
17 KiB
Go
521 lines
17 KiB
Go
|
// Copyright 2016 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 executor
|
||
|
|
||
|
import (
|
||
|
"fmt"
|
||
|
"strings"
|
||
|
|
||
|
"github.com/juju/errors"
|
||
|
"github.com/pingcap/tidb/ast"
|
||
|
"github.com/pingcap/tidb/column"
|
||
|
"github.com/pingcap/tidb/context"
|
||
|
"github.com/pingcap/tidb/model"
|
||
|
"github.com/pingcap/tidb/mysql"
|
||
|
"github.com/pingcap/tidb/sessionctx"
|
||
|
"github.com/pingcap/tidb/sessionctx/db"
|
||
|
"github.com/pingcap/tidb/sessionctx/variable"
|
||
|
"github.com/pingcap/tidb/table"
|
||
|
"github.com/pingcap/tidb/util/sqlexec"
|
||
|
"github.com/pingcap/tidb/util/types"
|
||
|
)
|
||
|
|
||
|
/***
|
||
|
* Grant Statement
|
||
|
* See: https://dev.mysql.com/doc/refman/5.7/en/grant.html
|
||
|
************************************************************************************/
|
||
|
var (
|
||
|
_ Executor = (*GrantExec)(nil)
|
||
|
)
|
||
|
|
||
|
// GrantExec executes GrantStmt.
|
||
|
type GrantExec struct {
|
||
|
Privs []*ast.PrivElem
|
||
|
ObjectType ast.ObjectTypeType
|
||
|
Level *ast.GrantLevel
|
||
|
Users []*ast.UserSpec
|
||
|
|
||
|
ctx context.Context
|
||
|
done bool
|
||
|
}
|
||
|
|
||
|
// Fields implements Executor Fields interface.
|
||
|
func (e *GrantExec) Fields() []*ast.ResultField {
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
// Next implements Execution Next interface.
|
||
|
func (e *GrantExec) Next() (*Row, error) {
|
||
|
if e.done {
|
||
|
return nil, nil
|
||
|
}
|
||
|
// Grant for each user
|
||
|
for _, user := range e.Users {
|
||
|
// Check if user exists.
|
||
|
userName, host := parseUser(user.User)
|
||
|
exists, err := userExists(e.ctx, userName, host)
|
||
|
if err != nil {
|
||
|
return nil, errors.Trace(err)
|
||
|
}
|
||
|
if !exists {
|
||
|
return nil, errors.Errorf("Unknown user: %s", user.User)
|
||
|
}
|
||
|
|
||
|
// If there is no privilege entry in corresponding table, insert a new one.
|
||
|
// DB scope: mysql.DB
|
||
|
// Table scope: mysql.Tables_priv
|
||
|
// Column scope: mysql.Columns_priv
|
||
|
switch e.Level.Level {
|
||
|
case ast.GrantLevelDB:
|
||
|
err := e.checkAndInitDBPriv(userName, host)
|
||
|
if err != nil {
|
||
|
return nil, errors.Trace(err)
|
||
|
}
|
||
|
case ast.GrantLevelTable:
|
||
|
err := e.checkAndInitTablePriv(userName, host)
|
||
|
if err != nil {
|
||
|
return nil, errors.Trace(err)
|
||
|
}
|
||
|
}
|
||
|
// Grant each priv to the user.
|
||
|
for _, priv := range e.Privs {
|
||
|
if len(priv.Cols) > 0 {
|
||
|
// Check column scope privilege entry.
|
||
|
// TODO: Check validity before insert new entry.
|
||
|
err1 := e.checkAndInitColumnPriv(userName, host, priv.Cols)
|
||
|
if err1 != nil {
|
||
|
return nil, errors.Trace(err1)
|
||
|
}
|
||
|
}
|
||
|
err2 := e.grantPriv(priv, user)
|
||
|
if err2 != nil {
|
||
|
return nil, errors.Trace(err2)
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
e.done = true
|
||
|
return nil, nil
|
||
|
}
|
||
|
|
||
|
// Close implements Executor Close interface.
|
||
|
func (e *GrantExec) Close() error {
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
// Check if DB scope privilege entry exists in mysql.DB.
|
||
|
// If unexists, insert a new one.
|
||
|
func (e *GrantExec) checkAndInitDBPriv(user string, host string) error {
|
||
|
db, err := e.getTargetSchema()
|
||
|
if err != nil {
|
||
|
return errors.Trace(err)
|
||
|
}
|
||
|
ok, err := dbUserExists(e.ctx, user, host, db.Name.O)
|
||
|
if err != nil {
|
||
|
return errors.Trace(err)
|
||
|
}
|
||
|
if ok {
|
||
|
return nil
|
||
|
}
|
||
|
// Entry does not exist for user-host-db. Insert a new entry.
|
||
|
return initDBPrivEntry(e.ctx, user, host, db.Name.O)
|
||
|
}
|
||
|
|
||
|
// Check if table scope privilege entry exists in mysql.Tables_priv.
|
||
|
// If unexists, insert a new one.
|
||
|
func (e *GrantExec) checkAndInitTablePriv(user string, host string) error {
|
||
|
db, tbl, err := e.getTargetSchemaAndTable()
|
||
|
if err != nil {
|
||
|
return errors.Trace(err)
|
||
|
}
|
||
|
ok, err := tableUserExists(e.ctx, user, host, db.Name.O, tbl.Meta().Name.O)
|
||
|
if err != nil {
|
||
|
return errors.Trace(err)
|
||
|
}
|
||
|
if ok {
|
||
|
return nil
|
||
|
}
|
||
|
// Entry does not exist for user-host-db-tbl. Insert a new entry.
|
||
|
return initTablePrivEntry(e.ctx, user, host, db.Name.O, tbl.Meta().Name.O)
|
||
|
}
|
||
|
|
||
|
// Check if column scope privilege entry exists in mysql.Columns_priv.
|
||
|
// If unexists, insert a new one.
|
||
|
func (e *GrantExec) checkAndInitColumnPriv(user string, host string, cols []*ast.ColumnName) error {
|
||
|
db, tbl, err := e.getTargetSchemaAndTable()
|
||
|
if err != nil {
|
||
|
return errors.Trace(err)
|
||
|
}
|
||
|
for _, c := range cols {
|
||
|
col := column.FindCol(tbl.Cols(), c.Name.L)
|
||
|
if col == nil {
|
||
|
return errors.Errorf("Unknown column: %s", c.Name.O)
|
||
|
}
|
||
|
ok, err := columnPrivEntryExists(e.ctx, user, host, db.Name.O, tbl.Meta().Name.O, col.Name.O)
|
||
|
if err != nil {
|
||
|
return errors.Trace(err)
|
||
|
}
|
||
|
if ok {
|
||
|
continue
|
||
|
}
|
||
|
// Entry does not exist for user-host-db-tbl-col. Insert a new entry.
|
||
|
err = initColumnPrivEntry(e.ctx, user, host, db.Name.O, tbl.Meta().Name.O, col.Name.O)
|
||
|
if err != nil {
|
||
|
return errors.Trace(err)
|
||
|
}
|
||
|
}
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
// Insert a new row into mysql.DB with empty privilege.
|
||
|
func initDBPrivEntry(ctx context.Context, user string, host string, db string) error {
|
||
|
sql := fmt.Sprintf(`INSERT INTO %s.%s (Host, User, DB) VALUES ("%s", "%s", "%s")`, mysql.SystemDB, mysql.DBTable, host, user, db)
|
||
|
_, err := ctx.(sqlexec.RestrictedSQLExecutor).ExecRestrictedSQL(ctx, sql)
|
||
|
return errors.Trace(err)
|
||
|
}
|
||
|
|
||
|
// Insert a new row into mysql.Tables_priv with empty privilege.
|
||
|
func initTablePrivEntry(ctx context.Context, user string, host string, db string, tbl string) error {
|
||
|
sql := fmt.Sprintf(`INSERT INTO %s.%s (Host, User, DB, Table_name, Table_priv, Column_priv) VALUES ("%s", "%s", "%s", "%s", "", "")`, mysql.SystemDB, mysql.TablePrivTable, host, user, db, tbl)
|
||
|
_, err := ctx.(sqlexec.RestrictedSQLExecutor).ExecRestrictedSQL(ctx, sql)
|
||
|
return errors.Trace(err)
|
||
|
}
|
||
|
|
||
|
// Insert a new row into mysql.Columns_priv with empty privilege.
|
||
|
func initColumnPrivEntry(ctx context.Context, user string, host string, db string, tbl string, col string) error {
|
||
|
sql := fmt.Sprintf(`INSERT INTO %s.%s (Host, User, DB, Table_name, Column_name, Column_priv) VALUES ("%s", "%s", "%s", "%s", "%s", "")`, mysql.SystemDB, mysql.ColumnPrivTable, host, user, db, tbl, col)
|
||
|
_, err := ctx.(sqlexec.RestrictedSQLExecutor).ExecRestrictedSQL(ctx, sql)
|
||
|
return errors.Trace(err)
|
||
|
}
|
||
|
|
||
|
// Grant priv to user in s.Level scope.
|
||
|
func (e *GrantExec) grantPriv(priv *ast.PrivElem, user *ast.UserSpec) error {
|
||
|
switch e.Level.Level {
|
||
|
case ast.GrantLevelGlobal:
|
||
|
return e.grantGlobalPriv(priv, user)
|
||
|
case ast.GrantLevelDB:
|
||
|
return e.grantDBPriv(priv, user)
|
||
|
case ast.GrantLevelTable:
|
||
|
if len(priv.Cols) == 0 {
|
||
|
return e.grantTablePriv(priv, user)
|
||
|
}
|
||
|
return e.grantColumnPriv(priv, user)
|
||
|
default:
|
||
|
return errors.Errorf("Unknown grant level: %#v", e.Level)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Manipulate mysql.user table.
|
||
|
func (e *GrantExec) grantGlobalPriv(priv *ast.PrivElem, user *ast.UserSpec) error {
|
||
|
asgns, err := composeGlobalPrivUpdate(priv.Priv)
|
||
|
if err != nil {
|
||
|
return errors.Trace(err)
|
||
|
}
|
||
|
userName, host := parseUser(user.User)
|
||
|
sql := fmt.Sprintf(`UPDATE %s.%s SET %s WHERE User="%s" AND Host="%s"`, mysql.SystemDB, mysql.UserTable, asgns, userName, host)
|
||
|
_, err = e.ctx.(sqlexec.RestrictedSQLExecutor).ExecRestrictedSQL(e.ctx, sql)
|
||
|
return errors.Trace(err)
|
||
|
}
|
||
|
|
||
|
// Manipulate mysql.db table.
|
||
|
func (e *GrantExec) grantDBPriv(priv *ast.PrivElem, user *ast.UserSpec) error {
|
||
|
db, err := e.getTargetSchema()
|
||
|
if err != nil {
|
||
|
return errors.Trace(err)
|
||
|
}
|
||
|
asgns, err := composeDBPrivUpdate(priv.Priv)
|
||
|
if err != nil {
|
||
|
return errors.Trace(err)
|
||
|
}
|
||
|
userName, host := parseUser(user.User)
|
||
|
sql := fmt.Sprintf(`UPDATE %s.%s SET %s WHERE User="%s" AND Host="%s" AND DB="%s";`, mysql.SystemDB, mysql.DBTable, asgns, userName, host, db.Name.O)
|
||
|
_, err = e.ctx.(sqlexec.RestrictedSQLExecutor).ExecRestrictedSQL(e.ctx, sql)
|
||
|
return errors.Trace(err)
|
||
|
}
|
||
|
|
||
|
// Manipulate mysql.tables_priv table.
|
||
|
func (e *GrantExec) grantTablePriv(priv *ast.PrivElem, user *ast.UserSpec) error {
|
||
|
db, tbl, err := e.getTargetSchemaAndTable()
|
||
|
if err != nil {
|
||
|
return errors.Trace(err)
|
||
|
}
|
||
|
userName, host := parseUser(user.User)
|
||
|
asgns, err := composeTablePrivUpdate(e.ctx, priv.Priv, userName, host, db.Name.O, tbl.Meta().Name.O)
|
||
|
if err != nil {
|
||
|
return errors.Trace(err)
|
||
|
}
|
||
|
sql := fmt.Sprintf(`UPDATE %s.%s SET %s WHERE User="%s" AND Host="%s" AND DB="%s" AND Table_name="%s";`, mysql.SystemDB, mysql.TablePrivTable, asgns, userName, host, db.Name.O, tbl.Meta().Name.O)
|
||
|
_, err = e.ctx.(sqlexec.RestrictedSQLExecutor).ExecRestrictedSQL(e.ctx, sql)
|
||
|
return errors.Trace(err)
|
||
|
}
|
||
|
|
||
|
// Manipulate mysql.tables_priv table.
|
||
|
func (e *GrantExec) grantColumnPriv(priv *ast.PrivElem, user *ast.UserSpec) error {
|
||
|
db, tbl, err := e.getTargetSchemaAndTable()
|
||
|
if err != nil {
|
||
|
return errors.Trace(err)
|
||
|
}
|
||
|
userName, host := parseUser(user.User)
|
||
|
for _, c := range priv.Cols {
|
||
|
col := column.FindCol(tbl.Cols(), c.Name.L)
|
||
|
if col == nil {
|
||
|
return errors.Errorf("Unknown column: %s", c)
|
||
|
}
|
||
|
asgns, err := composeColumnPrivUpdate(e.ctx, priv.Priv, userName, host, db.Name.O, tbl.Meta().Name.O, col.Name.O)
|
||
|
if err != nil {
|
||
|
return errors.Trace(err)
|
||
|
}
|
||
|
sql := fmt.Sprintf(`UPDATE %s.%s SET %s WHERE User="%s" AND Host="%s" AND DB="%s" AND Table_name="%s" AND Column_name="%s";`, mysql.SystemDB, mysql.ColumnPrivTable, asgns, userName, host, db.Name.O, tbl.Meta().Name.O, col.Name.O)
|
||
|
_, err = e.ctx.(sqlexec.RestrictedSQLExecutor).ExecRestrictedSQL(e.ctx, sql)
|
||
|
if err != nil {
|
||
|
return errors.Trace(err)
|
||
|
}
|
||
|
}
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
// Compose update stmt assignment list string for global scope privilege update.
|
||
|
func composeGlobalPrivUpdate(priv mysql.PrivilegeType) (string, error) {
|
||
|
if priv == mysql.AllPriv {
|
||
|
strs := make([]string, 0, len(mysql.Priv2UserCol))
|
||
|
for _, v := range mysql.Priv2UserCol {
|
||
|
strs = append(strs, fmt.Sprintf(`%s="Y"`, v))
|
||
|
}
|
||
|
return strings.Join(strs, ", "), nil
|
||
|
}
|
||
|
col, ok := mysql.Priv2UserCol[priv]
|
||
|
if !ok {
|
||
|
return "", errors.Errorf("Unknown priv: %v", priv)
|
||
|
}
|
||
|
return fmt.Sprintf(`%s="Y"`, col), nil
|
||
|
}
|
||
|
|
||
|
// Compose update stmt assignment list for db scope privilege update.
|
||
|
func composeDBPrivUpdate(priv mysql.PrivilegeType) (string, error) {
|
||
|
if priv == mysql.AllPriv {
|
||
|
strs := make([]string, 0, len(mysql.AllDBPrivs))
|
||
|
for _, p := range mysql.AllDBPrivs {
|
||
|
v, ok := mysql.Priv2UserCol[p]
|
||
|
if !ok {
|
||
|
return "", errors.Errorf("Unknown db privilege %v", priv)
|
||
|
}
|
||
|
strs = append(strs, fmt.Sprintf(`%s="Y"`, v))
|
||
|
}
|
||
|
return strings.Join(strs, ", "), nil
|
||
|
}
|
||
|
col, ok := mysql.Priv2UserCol[priv]
|
||
|
if !ok {
|
||
|
return "", errors.Errorf("Unknown priv: %v", priv)
|
||
|
}
|
||
|
return fmt.Sprintf(`%s="Y"`, col), nil
|
||
|
}
|
||
|
|
||
|
// Compose update stmt assignment list for table scope privilege update.
|
||
|
func composeTablePrivUpdate(ctx context.Context, priv mysql.PrivilegeType, name string, host string, db string, tbl string) (string, error) {
|
||
|
var newTablePriv, newColumnPriv string
|
||
|
if priv == mysql.AllPriv {
|
||
|
for _, p := range mysql.AllTablePrivs {
|
||
|
v, ok := mysql.Priv2SetStr[p]
|
||
|
if !ok {
|
||
|
return "", errors.Errorf("Unknown table privilege %v", p)
|
||
|
}
|
||
|
if len(newTablePriv) == 0 {
|
||
|
newTablePriv = v
|
||
|
} else {
|
||
|
newTablePriv = fmt.Sprintf("%s,%s", newTablePriv, v)
|
||
|
}
|
||
|
}
|
||
|
for _, p := range mysql.AllColumnPrivs {
|
||
|
v, ok := mysql.Priv2SetStr[p]
|
||
|
if !ok {
|
||
|
return "", errors.Errorf("Unknown column privilege %v", p)
|
||
|
}
|
||
|
if len(newColumnPriv) == 0 {
|
||
|
newColumnPriv = v
|
||
|
} else {
|
||
|
newColumnPriv = fmt.Sprintf("%s,%s", newColumnPriv, v)
|
||
|
}
|
||
|
}
|
||
|
} else {
|
||
|
currTablePriv, currColumnPriv, err := getTablePriv(ctx, name, host, db, tbl)
|
||
|
if err != nil {
|
||
|
return "", errors.Trace(err)
|
||
|
}
|
||
|
p, ok := mysql.Priv2SetStr[priv]
|
||
|
if !ok {
|
||
|
return "", errors.Errorf("Unknown priv: %v", priv)
|
||
|
}
|
||
|
if len(currTablePriv) == 0 {
|
||
|
newTablePriv = p
|
||
|
} else {
|
||
|
newTablePriv = fmt.Sprintf("%s,%s", currTablePriv, p)
|
||
|
}
|
||
|
for _, cp := range mysql.AllColumnPrivs {
|
||
|
if priv == cp {
|
||
|
if len(currColumnPriv) == 0 {
|
||
|
newColumnPriv = p
|
||
|
} else {
|
||
|
newColumnPriv = fmt.Sprintf("%s,%s", currColumnPriv, p)
|
||
|
}
|
||
|
break
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
return fmt.Sprintf(`Table_priv="%s", Column_priv="%s", Grantor="%s"`, newTablePriv, newColumnPriv, variable.GetSessionVars(ctx).User), nil
|
||
|
}
|
||
|
|
||
|
// Compose update stmt assignment list for column scope privilege update.
|
||
|
func composeColumnPrivUpdate(ctx context.Context, priv mysql.PrivilegeType, name string, host string, db string, tbl string, col string) (string, error) {
|
||
|
newColumnPriv := ""
|
||
|
if priv == mysql.AllPriv {
|
||
|
for _, p := range mysql.AllColumnPrivs {
|
||
|
v, ok := mysql.Priv2SetStr[p]
|
||
|
if !ok {
|
||
|
return "", errors.Errorf("Unknown column privilege %v", p)
|
||
|
}
|
||
|
if len(newColumnPriv) == 0 {
|
||
|
newColumnPriv = v
|
||
|
} else {
|
||
|
newColumnPriv = fmt.Sprintf("%s,%s", newColumnPriv, v)
|
||
|
}
|
||
|
}
|
||
|
} else {
|
||
|
currColumnPriv, err := getColumnPriv(ctx, name, host, db, tbl, col)
|
||
|
if err != nil {
|
||
|
return "", errors.Trace(err)
|
||
|
}
|
||
|
p, ok := mysql.Priv2SetStr[priv]
|
||
|
if !ok {
|
||
|
return "", errors.Errorf("Unknown priv: %v", priv)
|
||
|
}
|
||
|
if len(currColumnPriv) == 0 {
|
||
|
newColumnPriv = p
|
||
|
} else {
|
||
|
newColumnPriv = fmt.Sprintf("%s,%s", currColumnPriv, p)
|
||
|
}
|
||
|
}
|
||
|
return fmt.Sprintf(`Column_priv="%s"`, newColumnPriv), nil
|
||
|
}
|
||
|
|
||
|
// Helper function to check if the sql returns any row.
|
||
|
func recordExists(ctx context.Context, sql string) (bool, error) {
|
||
|
rs, err := ctx.(sqlexec.RestrictedSQLExecutor).ExecRestrictedSQL(ctx, sql)
|
||
|
if err != nil {
|
||
|
return false, errors.Trace(err)
|
||
|
}
|
||
|
defer rs.Close()
|
||
|
row, err := rs.Next()
|
||
|
if err != nil {
|
||
|
return false, errors.Trace(err)
|
||
|
}
|
||
|
return row != nil, nil
|
||
|
}
|
||
|
|
||
|
// Check if there is an entry with key user-host-db in mysql.DB.
|
||
|
func dbUserExists(ctx context.Context, name string, host string, db string) (bool, error) {
|
||
|
sql := fmt.Sprintf(`SELECT * FROM %s.%s WHERE User="%s" AND Host="%s" AND DB="%s";`, mysql.SystemDB, mysql.DBTable, name, host, db)
|
||
|
return recordExists(ctx, sql)
|
||
|
}
|
||
|
|
||
|
// Check if there is an entry with key user-host-db-tbl in mysql.Tables_priv.
|
||
|
func tableUserExists(ctx context.Context, name string, host string, db string, tbl string) (bool, error) {
|
||
|
sql := fmt.Sprintf(`SELECT * FROM %s.%s WHERE User="%s" AND Host="%s" AND DB="%s" AND Table_name="%s";`, mysql.SystemDB, mysql.TablePrivTable, name, host, db, tbl)
|
||
|
return recordExists(ctx, sql)
|
||
|
}
|
||
|
|
||
|
// Check if there is an entry with key user-host-db-tbl-col in mysql.Columns_priv.
|
||
|
func columnPrivEntryExists(ctx context.Context, name string, host string, db string, tbl string, col string) (bool, error) {
|
||
|
sql := fmt.Sprintf(`SELECT * FROM %s.%s WHERE User="%s" AND Host="%s" AND DB="%s" AND Table_name="%s" AND Column_name="%s";`, mysql.SystemDB, mysql.ColumnPrivTable, name, host, db, tbl, col)
|
||
|
return recordExists(ctx, sql)
|
||
|
}
|
||
|
|
||
|
// Get current table scope privilege set from mysql.Tables_priv.
|
||
|
// Return Table_priv and Column_priv.
|
||
|
func getTablePriv(ctx context.Context, name string, host string, db string, tbl string) (string, string, error) {
|
||
|
sql := fmt.Sprintf(`SELECT Table_priv, Column_priv FROM %s.%s WHERE User="%s" AND Host="%s" AND DB="%s" AND Table_name="%s";`, mysql.SystemDB, mysql.TablePrivTable, name, host, db, tbl)
|
||
|
rs, err := ctx.(sqlexec.RestrictedSQLExecutor).ExecRestrictedSQL(ctx, sql)
|
||
|
if err != nil {
|
||
|
return "", "", errors.Trace(err)
|
||
|
}
|
||
|
defer rs.Close()
|
||
|
row, err := rs.Next()
|
||
|
if err != nil {
|
||
|
return "", "", errors.Trace(err)
|
||
|
}
|
||
|
var tPriv, cPriv string
|
||
|
if row.Data[0].Kind() == types.KindMysqlSet {
|
||
|
tablePriv := row.Data[0].GetMysqlSet()
|
||
|
tPriv = tablePriv.Name
|
||
|
}
|
||
|
if row.Data[1].Kind() == types.KindMysqlSet {
|
||
|
columnPriv := row.Data[1].GetMysqlSet()
|
||
|
cPriv = columnPriv.Name
|
||
|
}
|
||
|
return tPriv, cPriv, nil
|
||
|
}
|
||
|
|
||
|
// Get current column scope privilege set from mysql.Columns_priv.
|
||
|
// Return Column_priv.
|
||
|
func getColumnPriv(ctx context.Context, name string, host string, db string, tbl string, col string) (string, error) {
|
||
|
sql := fmt.Sprintf(`SELECT Column_priv FROM %s.%s WHERE User="%s" AND Host="%s" AND DB="%s" AND Table_name="%s" AND Column_name="%s";`, mysql.SystemDB, mysql.ColumnPrivTable, name, host, db, tbl, col)
|
||
|
rs, err := ctx.(sqlexec.RestrictedSQLExecutor).ExecRestrictedSQL(ctx, sql)
|
||
|
if err != nil {
|
||
|
return "", errors.Trace(err)
|
||
|
}
|
||
|
defer rs.Close()
|
||
|
row, err := rs.Next()
|
||
|
if err != nil {
|
||
|
return "", errors.Trace(err)
|
||
|
}
|
||
|
cPriv := ""
|
||
|
if row.Data[0].Kind() == types.KindMysqlSet {
|
||
|
cPriv = row.Data[0].GetMysqlSet().Name
|
||
|
}
|
||
|
return cPriv, nil
|
||
|
}
|
||
|
|
||
|
// Find the schema by dbName.
|
||
|
func (e *GrantExec) getTargetSchema() (*model.DBInfo, error) {
|
||
|
dbName := e.Level.DBName
|
||
|
if len(dbName) == 0 {
|
||
|
// Grant *, use current schema
|
||
|
dbName = db.GetCurrentSchema(e.ctx)
|
||
|
if len(dbName) == 0 {
|
||
|
return nil, errors.New("Miss DB name for grant privilege.")
|
||
|
}
|
||
|
}
|
||
|
//check if db exists
|
||
|
schema := model.NewCIStr(dbName)
|
||
|
is := sessionctx.GetDomain(e.ctx).InfoSchema()
|
||
|
db, ok := is.SchemaByName(schema)
|
||
|
if !ok {
|
||
|
return nil, errors.Errorf("Unknown schema name: %s", dbName)
|
||
|
}
|
||
|
return db, nil
|
||
|
}
|
||
|
|
||
|
// Find the schema and table by dbName and tableName.
|
||
|
func (e *GrantExec) getTargetSchemaAndTable() (*model.DBInfo, table.Table, error) {
|
||
|
db, err := e.getTargetSchema()
|
||
|
if err != nil {
|
||
|
return nil, nil, errors.Trace(err)
|
||
|
}
|
||
|
name := model.NewCIStr(e.Level.TableName)
|
||
|
is := sessionctx.GetDomain(e.ctx).InfoSchema()
|
||
|
tbl, err := is.TableByName(db.Name, name)
|
||
|
if err != nil {
|
||
|
return nil, nil, errors.Trace(err)
|
||
|
}
|
||
|
return db, tbl, nil
|
||
|
}
|