Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
50 changes: 44 additions & 6 deletions ast/ast.go
Original file line number Diff line number Diff line change
Expand Up @@ -502,12 +502,15 @@ type Privilege interface {
isPrivilege()
}

func (PrivilegeOnTable) isPrivilege() {}
func (SelectPrivilegeOnChangeStream) isPrivilege() {}
func (SelectPrivilegeOnView) isPrivilege() {}
func (ExecutePrivilegeOnTableFunction) isPrivilege() {}
func (UsagePrivilegeOnSchema) isPrivilege() {}
func (RolePrivilege) isPrivilege() {}
func (PrivilegeOnTable) isPrivilege() {}
func (PrivilegeOnAllTablesInSchema) isPrivilege() {}
func (SelectPrivilegeOnChangeStream) isPrivilege() {}
func (SelectPrivilegeOnAllChangeStreamsInSchema) isPrivilege() {}
func (SelectPrivilegeOnView) isPrivilege() {}
func (SelectPrivilegeOnAllViewsInSchema) isPrivilege() {}
func (ExecutePrivilegeOnTableFunction) isPrivilege() {}
func (UsagePrivilegeOnSchema) isPrivilege() {}
func (RolePrivilege) isPrivilege() {}

// TablePrivilege represents privileges on table.
type TablePrivilege interface {
Expand Down Expand Up @@ -3533,6 +3536,17 @@ type PrivilegeOnTable struct {
Names []*Path // len(Names) > 0
}

// PrivilegeOnAllTablesInSchema is ON ALL TABLES IN SCHEMA privilege node in GRANT and REVOKE.
//
// {{.Privileges | sqlJoin ","}} ON ALL TABLES IN SCHEMA {{.Schemas | sqlJoin ", "}}
type PrivilegeOnAllTablesInSchema struct {
// pos = Privileges[0].pos
// end = Schemas[$].end

Privileges []TablePrivilege // len(Privileges) > 0
Schemas []*Path // len(Schemas) > 0
}

// SelectPrivilege is SELECT ON TABLE privilege node in GRANT and REVOKE.
//
// SELECT{{if .Columns}}({{.Columns | sqlJoin ","}}){{end}}
Expand Down Expand Up @@ -3594,6 +3608,18 @@ type SelectPrivilegeOnChangeStream struct {
Names []*Path // len(Names) > 0
}

// SelectPrivilegeOnAllChangeStreamsInSchema is SELECT ON ALL CHANGE STREAMS IN SCHEMA privilege node in GRANT and REVOKE.
//
// SELECT ON ALL CHANGE STREAMS IN SCHEMA {{.Schemas | sqlJoin ", "}}
type SelectPrivilegeOnAllChangeStreamsInSchema struct {
// pos = Select
// end = Schemas[$].end

Select token.Pos

Schemas []*Path // len(Schemas) > 0
}

// SelectPrivilegeOnView is SELECT ON VIEW privilege node in GRANT and REVOKE.
//
// SELECT ON VIEW {{.Names | sqlJoin ","}}
Expand All @@ -3606,6 +3632,18 @@ type SelectPrivilegeOnView struct {
Names []*Path // len(Names) > 0
}

// SelectPrivilegeOnAllViewsInSchema is SELECT ON ALL VIEWS IN SCHEMA privilege node in GRANT and REVOKE.
//
// SELECT ON ALL VIEWS IN SCHEMA {{.Schemas | sqlJoin ", "}}
type SelectPrivilegeOnAllViewsInSchema struct {
// pos = Select
// end = Schemas[$].end

Select token.Pos

Schemas []*Path // len(Schemas) > 0
}

// ExecutePrivilegeOnTableFunction is EXECUTE ON TABLE FUNCTION privilege node in GRANT and REVOKE.
//
// EXECUTE ON TABLE FUNCTION {{.Names | sqlJoin ","}}
Expand Down
24 changes: 24 additions & 0 deletions ast/pos.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

12 changes: 12 additions & 0 deletions ast/sql.go
Original file line number Diff line number Diff line change
Expand Up @@ -1133,6 +1133,10 @@ func (p *PrivilegeOnTable) SQL() string {
return sqlJoin(p.Privileges, ", ") + " ON TABLE " + sqlJoin(p.Names, ", ")
}

func (p *PrivilegeOnAllTablesInSchema) SQL() string {
return sqlJoin(p.Privileges, ", ") + " ON ALL TABLES IN SCHEMA " + sqlJoin(p.Schemas, ", ")
}

func (s *SelectPrivilege) SQL() string {
return "SELECT" +
strOpt(len(s.Columns) > 0, "("+sqlJoin(s.Columns, ", ")+")")
Expand All @@ -1156,10 +1160,18 @@ func (p *SelectPrivilegeOnChangeStream) SQL() string {
return "SELECT ON CHANGE STREAM " + sqlJoin(p.Names, ", ")
}

func (p *SelectPrivilegeOnAllChangeStreamsInSchema) SQL() string {
return "SELECT ON ALL CHANGE STREAMS IN SCHEMA " + sqlJoin(p.Schemas, ", ")
}

func (s *SelectPrivilegeOnView) SQL() string {
return "SELECT ON VIEW " + sqlJoin(s.Names, ", ")
}

func (s *SelectPrivilegeOnAllViewsInSchema) SQL() string {
return "SELECT ON ALL VIEWS IN SCHEMA " + sqlJoin(s.Schemas, ", ")
}

func (e *ExecutePrivilegeOnTableFunction) SQL() string {
return "EXECUTE ON TABLE FUNCTION " + sqlJoin(e.Names, ", ")
}
Expand Down
10 changes: 10 additions & 0 deletions ast/walk_internal.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

130 changes: 130 additions & 0 deletions parser.go
Original file line number Diff line number Diff line change
Expand Up @@ -4885,6 +4885,9 @@ func (p *Parser) parseRevoke(pos token.Pos) *ast.Revoke {
}

func (p *Parser) parsePrivilege() ast.Privilege {
if s := p.tryParseSelectPrivilegeOnAllViewsInSchema(); s != nil {
return s
}
if s := p.tryParseSelectPrivilegeOnView(); s != nil {
return s
}
Expand All @@ -4897,12 +4900,48 @@ func (p *Parser) parsePrivilege() ast.Privilege {
if r := p.tryParseRolePrivilege(); r != nil {
return r
}
if c := p.tryParseSelectPrivilegeOnAllChangeStreamsInSchema(); c != nil {
return c
}
if c := p.tryParseSelectPrivilegeOnChangeStream(); c != nil {
return c
}
if t := p.tryParsePrivilegeOnAllTablesInSchema(); t != nil {
return t
}
return p.parsePrivilegeOnTable()
}

func (p *Parser) tryParseSelectPrivilegeOnAllViewsInSchema() *ast.SelectPrivilegeOnAllViewsInSchema {
if p.Token.Kind != "SELECT" {
return nil
}
lexer := p.Clone()
pos := p.expect("SELECT").Pos
if p.Token.Kind != "ON" {
p.Lexer = lexer
return nil
}
p.expect("ON")
if p.Token.Kind != "ALL" {
p.Lexer = lexer
return nil
}
p.expect("ALL")
if !p.Token.IsKeywordLike("VIEWS") {
p.Lexer = lexer
return nil
}
p.expectKeywordLike("VIEWS")
p.expect("IN")
p.expectKeywordLike("SCHEMA")
schemas := parseCommaSeparatedList(p, p.parsePath)
return &ast.SelectPrivilegeOnAllViewsInSchema{
Select: pos,
Schemas: schemas,
}
}

func (p *Parser) tryParseSelectPrivilegeOnView() *ast.SelectPrivilegeOnView {
if p.Token.Kind != "SELECT" {
return nil
Expand Down Expand Up @@ -4976,6 +5015,38 @@ func (p *Parser) tryParseRolePrivilege() *ast.RolePrivilege {
}
}

func (p *Parser) tryParseSelectPrivilegeOnAllChangeStreamsInSchema() *ast.SelectPrivilegeOnAllChangeStreamsInSchema {
if p.Token.Kind != "SELECT" {
return nil
}
lexer := p.Clone()
pos := p.expect("SELECT").Pos
if p.Token.Kind != "ON" {
p.Lexer = lexer
return nil
}
p.expect("ON")
if p.Token.Kind != "ALL" {
p.Lexer = lexer
return nil
}
p.expect("ALL")
if !p.Token.IsKeywordLike("CHANGE") {
p.Lexer = lexer
return nil
}
p.expectKeywordLike("CHANGE")
p.expectKeywordLike("STREAMS")
p.expect("IN")
p.expectKeywordLike("SCHEMA")
schemas := parseCommaSeparatedList(p, p.parsePath)

return &ast.SelectPrivilegeOnAllChangeStreamsInSchema{
Select: pos,
Schemas: schemas,
}
}

func (p *Parser) tryParseSelectPrivilegeOnChangeStream() *ast.SelectPrivilegeOnChangeStream {
if p.Token.Kind != "SELECT" {
return nil
Expand All @@ -5001,6 +5072,33 @@ func (p *Parser) tryParseSelectPrivilegeOnChangeStream() *ast.SelectPrivilegeOnC
}
}

func (p *Parser) tryParsePrivilegeOnAllTablesInSchema() *ast.PrivilegeOnAllTablesInSchema {
lexer := p.Clone()
privileges := parseCommaSeparatedList(p, p.parseSchemaTablePrivilege)
if p.Token.Kind != "ON" {
p.Lexer = lexer
return nil
}
p.expect("ON")
if p.Token.Kind != "ALL" {
p.Lexer = lexer
return nil
}
p.expect("ALL")
if !p.Token.IsKeywordLike("TABLES") {
p.Lexer = lexer
return nil
}
p.expectKeywordLike("TABLES")
p.expect("IN")
p.expectKeywordLike("SCHEMA")
schemas := parseCommaSeparatedList(p, p.parsePath)
return &ast.PrivilegeOnAllTablesInSchema{
Privileges: privileges,
Schemas: schemas,
}
}

func (p *Parser) parsePrivilegeOnTable() *ast.PrivilegeOnTable {
privileges := parseCommaSeparatedList(p, p.parseTablePrivilege)
p.expect("ON")
Expand All @@ -5012,6 +5110,38 @@ func (p *Parser) parsePrivilegeOnTable() *ast.PrivilegeOnTable {
}
}

func (p *Parser) parseSchemaTablePrivilege() ast.TablePrivilege {
pos := p.Token.Pos
switch {
case p.Token.Kind == "SELECT":
p.nextToken()
return &ast.SelectPrivilege{
Select: pos,
Rparen: token.InvalidPos,
}
case p.Token.IsKeywordLike("INSERT"):
p.nextToken()
return &ast.InsertPrivilege{
Insert: pos,
Rparen: token.InvalidPos,
}
case p.Token.IsKeywordLike("UPDATE"):
p.nextToken()
return &ast.UpdatePrivilege{
Update: pos,
Rparen: token.InvalidPos,
}
case p.Token.IsKeywordLike("DELETE"):
p.nextToken()
return &ast.DeletePrivilege{
Delete: pos,
}
default:
p.panicfAtToken(&p.Token, "expected privilege token: SELECT, INSERT, UPDATE, DELETE, but: %s", p.Token.AsString)
return nil
}
}

func (p *Parser) parseTablePrivilege() ast.TablePrivilege {
pos := p.Token.Pos
switch {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
GRANT SELECT ON ALL CHANGE STREAMS IN SCHEMA sch TO ROLE r
1 change: 1 addition & 0 deletions testdata/input/ddl/grant_on_all_tables_in_schema.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
GRANT SELECT, DELETE ON ALL TABLES IN SCHEMA sch1, sch2 TO ROLE r
1 change: 1 addition & 0 deletions testdata/input/ddl/grant_on_all_views_in_schema.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
GRANT SELECT ON ALL VIEWS IN SCHEMA sch TO ROLE r
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
REVOKE SELECT ON ALL CHANGE STREAMS IN SCHEMA sch1, sch2 FROM ROLE r
1 change: 1 addition & 0 deletions testdata/input/ddl/revoke_on_all_tables_in_schema.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
REVOKE INSERT, UPDATE ON ALL TABLES IN SCHEMA db.sch FROM ROLE r
1 change: 1 addition & 0 deletions testdata/input/ddl/revoke_on_all_views_in_schema.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
REVOKE SELECT ON ALL VIEWS IN SCHEMA db.sch FROM ROLE r
30 changes: 30 additions & 0 deletions testdata/result/ddl/grant_on_all_change_streams_in_schema.sql.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
--- grant_on_all_change_streams_in_schema.sql
GRANT SELECT ON ALL CHANGE STREAMS IN SCHEMA sch TO ROLE r

--- AST
&ast.Grant{
Privilege: &ast.SelectPrivilegeOnAllChangeStreamsInSchema{
Select: 6,
Schemas: []*ast.Path{
&ast.Path{
Idents: []*ast.Ident{
&ast.Ident{
NamePos: 45,
NameEnd: 48,
Name: "sch",
},
},
},
},
},
Roles: []*ast.Ident{
&ast.Ident{
NamePos: 57,
NameEnd: 58,
Name: "r",
},
},
}

--- SQL
GRANT SELECT ON ALL CHANGE STREAMS IN SCHEMA sch TO ROLE r
Loading
Loading