Skip to content

Commit a7edf6b

Browse files
authored
feat(spanner/spansql): support fine-grained access control DDL syntax (#6691)
* feat(spanner/spannersql): support create or drop role clause * feat(spanner/spannersql): support grant or revoke role clause * fix(spanner/spannersql): fix variable name * fix(spanner/spansql): adjust case * fix(spanner/spansql): fix duplicate token check * fix(spanner/spansql): gofmt -s -d -l -w . * feat(spanner/spansql): fix debug log message * feat(spanner/spansql): modify func name from parseCommaListWithBraket to parseCommaList
1 parent fcab05f commit a7edf6b

File tree

5 files changed

+590
-4
lines changed

5 files changed

+590
-4
lines changed

spanner/spansql/parser.go

Lines changed: 232 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -996,6 +996,9 @@ func (p *parser) parseDDLStmt() (DDLStmt, *parseError) {
996996
} else if p.sniff("CREATE", "VIEW") || p.sniff("CREATE", "OR", "REPLACE", "VIEW") {
997997
cv, err := p.parseCreateView()
998998
return cv, err
999+
} else if p.sniff("CREATE", "ROLE") {
1000+
cr, err := p.parseCreateRole()
1001+
return cr, err
9991002
} else if p.sniff("ALTER", "TABLE") {
10001003
a, err := p.parseAlterTable()
10011004
return a, err
@@ -1005,6 +1008,7 @@ func (p *parser) parseDDLStmt() (DDLStmt, *parseError) {
10051008
// DROP TABLE table_name
10061009
// DROP INDEX index_name
10071010
// DROP VIEW view_name
1011+
// DROP ROLE role_name
10081012
// DROP CHANGE STREAM change_stream_name
10091013
tok := p.next()
10101014
if tok.err != nil {
@@ -1031,6 +1035,12 @@ func (p *parser) parseDDLStmt() (DDLStmt, *parseError) {
10311035
return nil, err
10321036
}
10331037
return &DropView{Name: name, Position: pos}, nil
1038+
case tok.caseEqual("ROLE"):
1039+
name, err := p.parseTableOrIndexOrColumnName()
1040+
if err != nil {
1041+
return nil, err
1042+
}
1043+
return &DropRole{Name: name, Position: pos}, nil
10341044
case tok.caseEqual("CHANGE"):
10351045
if err := p.expect("STREAM"); err != nil {
10361046
return nil, err
@@ -1044,6 +1054,12 @@ func (p *parser) parseDDLStmt() (DDLStmt, *parseError) {
10441054
} else if p.sniff("ALTER", "DATABASE") {
10451055
a, err := p.parseAlterDatabase()
10461056
return a, err
1057+
} else if p.eat("GRANT") {
1058+
a, err := p.parseGrantRole()
1059+
return a, err
1060+
} else if p.eat("REVOKE") {
1061+
a, err := p.parseRevokeRole()
1062+
return a, err
10471063
} else if p.sniff("CREATE", "CHANGE", "STREAM") {
10481064
cs, err := p.parseCreateChangeStream()
10491065
return cs, err
@@ -1297,6 +1313,176 @@ func (p *parser) parseCreateView() (*CreateView, *parseError) {
12971313
}, nil
12981314
}
12991315

1316+
func (p *parser) parseCreateRole() (*CreateRole, *parseError) {
1317+
debugf("parseCreateRole: %v", p)
1318+
1319+
/*
1320+
CREATE ROLE database_role_name
1321+
*/
1322+
1323+
if err := p.expect("CREATE"); err != nil {
1324+
return nil, err
1325+
}
1326+
pos := p.Pos()
1327+
if err := p.expect("ROLE"); err != nil {
1328+
return nil, err
1329+
}
1330+
rname, err := p.parseTableOrIndexOrColumnName()
1331+
if err != nil {
1332+
return nil, err
1333+
}
1334+
cr := &CreateRole{
1335+
Name: rname,
1336+
1337+
Position: pos,
1338+
}
1339+
1340+
return cr, nil
1341+
}
1342+
1343+
func (p *parser) parseGrantRole() (*GrantRole, *parseError) {
1344+
pos := p.Pos()
1345+
g := &GrantRole{
1346+
Position: pos,
1347+
}
1348+
if p.eat("ROLE") {
1349+
roleList, err := p.parseGrantOrRevokeRoleList("TO")
1350+
if err != nil {
1351+
return nil, err
1352+
}
1353+
g.GrantRoleNames = roleList
1354+
} else {
1355+
var privs []Privilege
1356+
privs, err := p.parsePrivileges()
1357+
if err != nil {
1358+
return nil, err
1359+
}
1360+
g.Privileges = privs
1361+
var tableList []ID
1362+
f := func(p *parser) *parseError {
1363+
table, err := p.parseTableOrIndexOrColumnName()
1364+
if err != nil {
1365+
return err
1366+
}
1367+
tableList = append(tableList, table)
1368+
return nil
1369+
}
1370+
if err := p.parseCommaListWithEnds(f, "TO", "ROLE"); err != nil {
1371+
return nil, err
1372+
}
1373+
g.TableNames = tableList
1374+
}
1375+
list, err := p.parseIDList()
1376+
if err != nil {
1377+
return nil, err
1378+
}
1379+
g.ToRoleNames = list
1380+
1381+
return g, nil
1382+
}
1383+
1384+
func (p *parser) parseRevokeRole() (*RevokeRole, *parseError) {
1385+
pos := p.Pos()
1386+
r := &RevokeRole{
1387+
Position: pos,
1388+
}
1389+
if p.eat("ROLE") {
1390+
roleList, err := p.parseGrantOrRevokeRoleList("FROM")
1391+
if err != nil {
1392+
return nil, err
1393+
}
1394+
r.RevokeRoleNames = roleList
1395+
} else {
1396+
var privs []Privilege
1397+
privs, err := p.parsePrivileges()
1398+
if err != nil {
1399+
return nil, err
1400+
}
1401+
r.Privileges = privs
1402+
var tableList []ID
1403+
f := func(p *parser) *parseError {
1404+
table, err := p.parseTableOrIndexOrColumnName()
1405+
if err != nil {
1406+
return err
1407+
}
1408+
tableList = append(tableList, table)
1409+
return nil
1410+
}
1411+
if err := p.parseCommaListWithEnds(f, "FROM", "ROLE"); err != nil {
1412+
return nil, err
1413+
}
1414+
r.TableNames = tableList
1415+
}
1416+
list, err := p.parseIDList()
1417+
if err != nil {
1418+
return nil, err
1419+
}
1420+
r.FromRoleNames = list
1421+
1422+
return r, nil
1423+
}
1424+
func (p *parser) parseGrantOrRevokeRoleList(end string) ([]ID, *parseError) {
1425+
var roleList []ID
1426+
f := func(p *parser) *parseError {
1427+
role, err := p.parseTableOrIndexOrColumnName()
1428+
if err != nil {
1429+
return err
1430+
}
1431+
roleList = append(roleList, role)
1432+
return nil
1433+
}
1434+
err := p.parseCommaListWithEnds(f, end, "ROLE")
1435+
if err != nil {
1436+
return nil, err
1437+
}
1438+
return roleList, nil
1439+
}
1440+
1441+
func (p *parser) parsePrivileges() ([]Privilege, *parseError) {
1442+
var privs []Privilege
1443+
for {
1444+
tok := p.next()
1445+
if tok.err != nil {
1446+
return []Privilege{}, tok.err
1447+
}
1448+
1449+
priv := Privilege{}
1450+
switch {
1451+
default:
1452+
return []Privilege{}, p.errorf("got %q, want SELECT or UPDATE or INSERT or DELETE", tok.value)
1453+
case tok.caseEqual("SELECT"):
1454+
priv.Type = PrivilegeTypeSelect
1455+
case tok.caseEqual("UPDATE"):
1456+
priv.Type = PrivilegeTypeUpdate
1457+
case tok.caseEqual("INSERT"):
1458+
priv.Type = PrivilegeTypeInsert
1459+
case tok.caseEqual("DELETE"):
1460+
priv.Type = PrivilegeTypeDelete
1461+
}
1462+
// can grant DELETE only at the table level.
1463+
// https://cloud.google.com/spanner/docs/reference/standard-sql/data-definition-language#notes_and_restrictions
1464+
if p.sniff("(") && !tok.caseEqual("DELETE") {
1465+
list, err := p.parseColumnNameList()
1466+
if err != nil {
1467+
return nil, err
1468+
}
1469+
priv.Columns = list
1470+
}
1471+
privs = append(privs, priv)
1472+
tok = p.next()
1473+
if tok.err != nil {
1474+
return []Privilege{}, tok.err
1475+
}
1476+
if tok.value == "," {
1477+
continue
1478+
} else if tok.caseEqual("ON") && p.eat("TABLE") {
1479+
break
1480+
} else {
1481+
return []Privilege{}, p.errorf("got %q, want , or ON TABLE", tok.value)
1482+
}
1483+
}
1484+
return privs, nil
1485+
}
13001486
func (p *parser) parseAlterTable() (*AlterTable, *parseError) {
13011487
debugf("parseAlterTable: %v", p)
13021488

@@ -2053,6 +2239,23 @@ func (p *parser) parseColumnNameList() ([]ID, *parseError) {
20532239
return list, err
20542240
}
20552241

2242+
func (p *parser) parseIDList() ([]ID, *parseError) {
2243+
var list []ID
2244+
for {
2245+
n, err := p.parseTableOrIndexOrColumnName()
2246+
if err != nil {
2247+
return nil, err
2248+
}
2249+
list = append(list, n)
2250+
2251+
if p.eat(",") {
2252+
continue
2253+
}
2254+
break
2255+
}
2256+
return list, nil
2257+
}
2258+
20562259
func (p *parser) parseCreateChangeStream() (*CreateChangeStream, *parseError) {
20572260
debugf("parseCreateChangeStream: %v", p)
20582261

@@ -3898,7 +4101,7 @@ func (p *parser) parseHints(hints map[string]string) (map[string]string, *parseE
38984101

38994102
func (p *parser) parseTableOrIndexOrColumnName() (ID, *parseError) {
39004103
/*
3901-
table_name and column_name and index_name:
4104+
table_name and column_name and index_name and role_name:
39024105
{a—z|A—Z}[{a—z|A—Z|0—9|_}+]
39034106
*/
39044107

@@ -4001,3 +4204,31 @@ func (p *parser) parseCommaList(bra, ket string, f func(*parser) *parseError) *p
40014204
}
40024205
}
40034206
}
4207+
4208+
// parseCommaListWithEnds parses a comma-separated list to expected ends,
4209+
// delegating to f for the individual element parsing.
4210+
// Only invoke this with symbols as end; they are matched case insensitively.
4211+
func (p *parser) parseCommaListWithEnds(f func(*parser) *parseError, end ...string) *parseError {
4212+
if p.eat(end...) {
4213+
return nil
4214+
}
4215+
for {
4216+
err := f(p)
4217+
if err != nil {
4218+
return err
4219+
}
4220+
if p.eat(end...) {
4221+
return nil
4222+
}
4223+
4224+
tok := p.next()
4225+
if tok.err != nil {
4226+
return err
4227+
}
4228+
if tok.value == "," {
4229+
continue
4230+
} else if tok.value == ";" {
4231+
return nil
4232+
}
4233+
}
4234+
}

0 commit comments

Comments
 (0)