Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Shenli/show grants #473

Merged
merged 6 commits into from
Oct 30, 2015
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions mysql/const.go
Original file line number Diff line number Diff line change
Expand Up @@ -252,3 +252,6 @@ var AllTablePrivs = []PrivilegeType{SelectPriv, InsertPriv, UpdatePriv, DeletePr

// AllColumnPrivs is all the privileges in column scope.
var AllColumnPrivs = []PrivilegeType{SelectPriv, InsertPriv, UpdatePriv}

// AllPrivilegeLiteral is the string literal for All Privilege.
const AllPrivilegeLiteral = "ALL PRIVILEGES"
16 changes: 15 additions & 1 deletion parser/parser.y
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,7 @@ import (
ge ">="
global "GLOBAL"
grant "GRANT"
grants "GRANTS"
group "GROUP"
groupConcat "GROUP_CONCAT"
having "HAVING"
Expand Down Expand Up @@ -1700,7 +1701,7 @@ UnReservedKeyword:
| "START" | "GLOBAL" | "TABLES"| "TEXT" | "TIME" | "TIMESTAMP" | "TRANSACTION" | "TRUNCATE" | "UNKNOWN"
| "VALUE" | "WARNINGS" | "YEAR" | "MODE" | "WEEK" | "ANY" | "SOME" | "USER" | "IDENTIFIED" | "COLLATION"
| "COMMENT" | "AVG_ROW_LENGTH" | "CONNECTION" | "CHECKSUM" | "COMPRESSION" | "KEY_BLOCK_SIZE" | "MAX_ROWS" | "MIN_ROWS"
| "NATIONAL" | "ROW" | "QUARTER" | "ESCAPE"
| "NATIONAL" | "ROW" | "QUARTER" | "ESCAPE" | "GRANTS"

NotKeywordToken:
"ABS" | "COALESCE" | "CONCAT" | "CONCAT_WS" | "COUNT" | "DAY" | "DATE_ADD" | "DAYOFMONTH" | "DAYOFWEEK" | "DAYOFYEAR" | "FOUND_ROWS" | "GROUP_CONCAT"
Expand Down Expand Up @@ -3453,6 +3454,19 @@ ShowStmt:
TableIdent: $4.(table.Ident),
}
}
| "SHOW" "GRANTS"
{
// See: https://dev.mysql.com/doc/refman/5.7/en/show-grants.html
$$ = &stmts.ShowStmt{Target: stmt.ShowGrants}
}
| "SHOW" "GRANTS" "FOR" Username
{
// See: https://dev.mysql.com/doc/refman/5.7/en/show-grants.html
$$ = &stmts.ShowStmt{
Target: stmt.ShowGrants,
User: $4.(string),
}
}

ShowLikeOrWhereOpt:
{
Expand Down
4 changes: 3 additions & 1 deletion parser/parser_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ func (s *testParserSuite) TestSimple(c *C) {
"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", "escape",
"max_rows", "min_rows", "national", "row", "quarter", "escape", "grants",
}
for _, kw := range unreservedKws {
src := fmt.Sprintf("SELECT %s FROM tbl;", kw)
Expand Down Expand Up @@ -252,6 +252,8 @@ func (s *testParserSuite) TestDMLStmt(c *C) {
{"SHOW GLOBAL VARIABLES WHERE Variable_name = 'autocommit'", true},
{`SHOW FULL TABLES FROM icar_qa LIKE play_evolutions`, true},
{`SHOW FULL TABLES WHERE Table_Type != 'VIEW'`, true},
{`SHOW GRANTS`, true},
{`SHOW GRANTS FOR 'test'@'localhost'`, true},

// For default value
{"CREATE TABLE sbtest (id INTEGER UNSIGNED NOT NULL AUTO_INCREMENT, k integer UNSIGNED DEFAULT '0' NOT NULL, c char(120) DEFAULT '' NOT NULL, pad char(60) DEFAULT '' NOT NULL, PRIMARY KEY (id) )", true},
Expand Down
3 changes: 3 additions & 0 deletions parser/scanner.l
Original file line number Diff line number Diff line change
Expand Up @@ -319,6 +319,7 @@ full {f}{u}{l}{l}
fulltext {f}{u}{l}{l}{t}{e}{x}{t}
global {g}{l}{o}{b}{a}{l}
grant {g}{r}{a}{n}{t}
grants {g}{r}{a}{n}{t}{s}
group {g}{r}{o}{u}{p}
group_concat {g}{r}{o}{u}{p}_{c}{o}{n}{c}{a}{t}
having {h}{a}{v}{i}{n}{g}
Expand Down Expand Up @@ -692,6 +693,8 @@ year_month {y}{e}{a}{r}_{m}{o}{n}{t}{h}
return full
{fulltext} return fulltext
{grant} return grant
{grants} lval.item = string(l.val)
return grants
{group} return group
{group_concat} lval.item = string(l.val)
return groupConcat
Expand Down
24 changes: 23 additions & 1 deletion plan/plans/show.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import (
"github.com/pingcap/tidb/model"
"github.com/pingcap/tidb/mysql"
"github.com/pingcap/tidb/plan"
"github.com/pingcap/tidb/privilege"
"github.com/pingcap/tidb/sessionctx"
"github.com/pingcap/tidb/sessionctx/variable"
"github.com/pingcap/tidb/stmt"
Expand All @@ -53,6 +54,7 @@ type ShowPlan struct {
Where expression.Expression
rows []*plan.Row
cursor int
User string // ShowGrants need to know username.
}

func (s *ShowPlan) isColOK(c *column.Col) bool {
Expand Down Expand Up @@ -107,6 +109,8 @@ func (s *ShowPlan) GetFields() []*field.ResultField {
mysql.TypeVarchar, mysql.TypeVarchar, mysql.TypeLonglong}
case stmt.ShowCreateTable:
names = []string{"Table", "Create Table"}
case stmt.ShowGrants:
names = []string{fmt.Sprintf("Grants for %s", s.User)}
}
fields := make([]*field.ResultField, 0, len(names))
for i, name := range names {
Expand Down Expand Up @@ -164,6 +168,8 @@ func (s *ShowPlan) fetchAll(ctx context.Context) error {
return s.fetchShowCollation(ctx)
case stmt.ShowCreateTable:
return s.fetchShowCreateTable(ctx)
case stmt.ShowGrants:
return s.fetchShowGrants(ctx)
}
return nil
}
Expand All @@ -186,7 +192,6 @@ func (s *ShowPlan) evalCondition(ctx context.Context, m map[interface{}]interfac
if cond == nil {
return true, nil
}

return expression.EvalBoolExpr(ctx, cond, m)
}

Expand Down Expand Up @@ -498,3 +503,20 @@ func (s *ShowPlan) fetchShowCreateTable(ctx context.Context) error {

return nil
}

func (s *ShowPlan) fetchShowGrants(ctx context.Context) error {
// Get checker
checker := privilege.GetPrivilegeChecker(ctx)
if checker == nil {
return errors.New("Miss privilege checker!")
}
gs, err := checker.ShowGrants(ctx, s.User)
if err != nil {
return errors.Trace(err)
}
for _, g := range gs {
data := []interface{}{g}
s.rows = append(s.rows, &plan.Row{Data: data})
}
return nil
}
83 changes: 79 additions & 4 deletions plan/plans/show_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ package plans_test

import (
"database/sql"
"fmt"

. "github.com/pingcap/check"
"github.com/pingcap/tidb"
Expand All @@ -34,17 +35,52 @@ import (
type testShowSuit struct {
txn kv.Transaction
ctx context.Context

store kv.Storage
dbName string

createDBSQL string
dropDBSQL string
useDBSQL string
createTableSQL string
createSystemDBSQL string
createUserTableSQL string
createDBPrivTableSQL string
createTablePrivTableSQL string
createColumnPrivTableSQL string
}

var _ = Suite(&testShowSuit{})

func (p *testShowSuit) SetUpSuite(c *C) {
var err error
store, err := tidb.NewStore(tidb.EngineGoLevelDBMemory)
c.Assert(err, IsNil)
p.ctx = mock.NewContext()
p.txn, _ = store.Begin()
variable.BindSessionVars(p.ctx)

p.dbName = "testshowplan"
p.store = newStore(c, p.dbName)
p.txn, _ = p.store.Begin()
se := newSession(c, p.store, p.dbName)
p.createDBSQL = fmt.Sprintf("create database if not exists %s;", p.dbName)
p.dropDBSQL = fmt.Sprintf("drop database if exists %s;", p.dbName)
p.useDBSQL = fmt.Sprintf("use %s;", p.dbName)
p.createTableSQL = `CREATE TABLE test(id INT NOT NULL DEFAULT 1, name varchar(255), PRIMARY KEY(id));`

mustExecSQL(c, se, p.createDBSQL)
mustExecSQL(c, se, p.useDBSQL)
mustExecSQL(c, se, p.createTableSQL)

p.createSystemDBSQL = fmt.Sprintf("create database if not exists %s;", mysql.SystemDB)
p.createUserTableSQL = tidb.CreateUserTable
p.createDBPrivTableSQL = tidb.CreateDBPrivTable
p.createTablePrivTableSQL = tidb.CreateTablePrivTable
p.createColumnPrivTableSQL = tidb.CreateColumnPrivTable

mustExecSQL(c, se, p.createSystemDBSQL)
mustExecSQL(c, se, p.createUserTableSQL)
mustExecSQL(c, se, p.createDBPrivTableSQL)
mustExecSQL(c, se, p.createTablePrivTableSQL)
mustExecSQL(c, se, p.createColumnPrivTableSQL)

}

func (p *testShowSuit) TearDownSuite(c *C) {
Expand Down Expand Up @@ -213,3 +249,42 @@ func (p *testShowSuit) TestShowTables(c *C) {
rows.Next()
c.Assert(rows.Err(), NotNil)
}

func (p *testShowSuit) TestShowGrants(c *C) {
se := newSession(c, p.store, p.dbName)
ctx, _ := se.(context.Context)
mustExecSQL(c, se, `CREATE USER 'test'@'localhost' identified by '123';`)
variable.GetSessionVars(ctx).User = `test@localhost`
mustExecSQL(c, se, `GRANT Index ON *.* TO 'test'@'localhost';`)

pln := &plans.ShowPlan{
Target: stmt.ShowGrants,
User: `test@localhost`,
}
row, err := pln.Next(ctx)
c.Assert(err, IsNil)
c.Assert(row.Data[0], Equals, `GRANT Index ON *.* TO 'test'@'localhost'`)

fs := pln.GetFields()
c.Assert(fs, HasLen, 1)
c.Assert(fs[0].Name, Equals, `Grants for test@localhost`)
}

func mustExecSQL(c *C, se tidb.Session, sql string) {
_, err := se.Execute(sql)
c.Assert(err, IsNil)
}

func newStore(c *C, dbPath string) kv.Storage {
store, err := tidb.NewStore("memory" + "://" + dbPath)
c.Assert(err, IsNil)
return store
}

func newSession(c *C, store kv.Storage, dbName string) tidb.Session {
se, err := tidb.CreateSession(store)
c.Assert(err, IsNil)
mustExecSQL(c, se, "create database if not exists "+dbName)
mustExecSQL(c, se, "use "+dbName)
return se
}
2 changes: 2 additions & 0 deletions privilege/privilege.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ type Checker interface {
// If tbl is nil, only check global/db scope privileges.
// If tbl is not nil, check global/db/table scope privileges.
Check(ctx context.Context, db *model.DBInfo, tbl *model.TableInfo, privilege mysql.PrivilegeType) (bool, error)
// Show granted privileges for user.
ShowGrants(ctx context.Context, user string) ([]string, error)
}

const key keyType = 0
Expand Down
Loading