Skip to content

Commit

Permalink
Merge branch 'revoke'
Browse files Browse the repository at this point in the history
  • Loading branch information
nene committed Nov 28, 2024
2 parents 60216ee + aba25cf commit 424ffca
Show file tree
Hide file tree
Showing 5 changed files with 210 additions and 22 deletions.
26 changes: 22 additions & 4 deletions src/cst/Dcl.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,11 @@ export type AllDclNodes =
| GrantResource
| GrantedByClause;

export type AllDclStatements = GrantRoleStmt | GrantPrivilegeStmt | RevokeStmt;
export type AllDclStatements =
| GrantRoleStmt
| GrantPrivilegeStmt
| RevokeRoleStmt
| RevokePrivilegeStmt;

// GRANT role ON resource TO user
export interface GrantRoleStmt extends BaseNode {
Expand Down Expand Up @@ -211,9 +215,9 @@ export interface GrantedByClause extends BaseNode {

type GrantRoleSpecification = Identifier;

// REVOKE
export interface RevokeStmt extends BaseNode {
type: "revoke_stmt";
// REVOKE role ON resource FROM user
export interface RevokeRoleStmt extends BaseNode {
type: "revoke_role_stmt";
revokeKw: Keyword<"REVOKE">;
roles: ListExpr<Identifier>;
onKw: Keyword<"ON">;
Expand All @@ -224,3 +228,17 @@ export interface RevokeStmt extends BaseNode {
fromKw: Keyword<"FROM">;
users: ListExpr<StringLiteral>;
}

// REVOKE privilege ON resource FROM roles
export interface RevokePrivilegeStmt extends BaseNode {
type: "revoke_privilege_stmt";
revokeKw: Keyword<"REVOKE">;
grantOptionForKw?: [Keyword<"GRANT">, Keyword<"OPTION">, Keyword<"FOR">];
privileges: ListExpr<Privilege> | AllPrivileges;
onKw: Keyword<"ON">;
resource: GrantResource;
fromKw: Keyword<"FROM">;
roles: ListExpr<GrantRoleSpecification>;
grantedBy?: GrantedByClause;
behaviorKw: Keyword<"CASCADE" | "RESTRICT">;
}
29 changes: 25 additions & 4 deletions src/parser.pegjs
Original file line number Diff line number Diff line change
Expand Up @@ -4732,8 +4732,8 @@ release_savepoint_stmt
* ------------------------------------------------------------------------------------ *
*/
dcl_statement
= &bigquery x:(grant_role_stmt / revoke_stmt) { return x; }
/ &postgres x:(grant_privilege_stmt) { return x; }
= &bigquery x:(grant_role_stmt / revoke_role_stmt) { return x; }
/ &postgres x:(grant_privilege_stmt / revoke_privilege_stmt) { return x; }

grant_role_stmt
= kw:(GRANT __) roles:(list$ident __)
Expand Down Expand Up @@ -4858,12 +4858,12 @@ granted_by_clause
return loc({ type: "granted_by_clause", grantedByKw: read(kw), role });
}

revoke_stmt
revoke_role_stmt
= kw:(REVOKE __) roles:(list$ident __)
onKw:(ON __) resType:(resource_type_kw __) resName:(entity_name __)
fromKw:(FROM __) users:(list$string_literal) {
return loc({
type: "revoke_stmt",
type: "revoke_role_stmt",
revokeKw: read(kw),
roles: read(roles),
onKw: read(onKw),
Expand All @@ -4880,6 +4880,27 @@ resource_type_kw
/ VIEW
/ kw:(EXTERNAL __ TABLE) { return read(kw); }

revoke_privilege_stmt
= kw:(REVOKE __) grantOptionForKw:(GRANT __ OPTION __ FOR __)?
privileges:((list$privilege / all_privileges) __)
onKw:(ON __) resource:(grant_resource __)
fromKw:(FROM __) roles:list$role_specification
grantedBy:(__ granted_by_clause)?
behaviorKw:(__ (CASCADE / RESTRICT))? {
return loc({
type: "revoke_privilege_stmt",
revokeKw: read(kw),
grantOptionForKw: read(grantOptionForKw),
privileges: read(privileges),
onKw: read(onKw),
resource: read(resource),
fromKw: read(fromKw),
roles,
grantedBy: read(grantedBy),
behaviorKw: read(behaviorKw),
});
}

/**
* ------------------------------------------------------------------------------------ *
* *
Expand Down
14 changes: 13 additions & 1 deletion src/showNode/dcl.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ export const dclMap: FullTransformMap<string, AllDclNodes> = {
grant_resource_type: (node) => show([node.typeKw, node.types]),
granted_by_clause: (node) => show([node.grantedByKw, node.role]),

revoke_stmt: (node) =>
revoke_role_stmt: (node) =>
show([
node.revokeKw,
node.roles,
Expand All @@ -61,4 +61,16 @@ export const dclMap: FullTransformMap<string, AllDclNodes> = {
node.fromKw,
node.users,
]),
revoke_privilege_stmt: (node) =>
show([
node.revokeKw,
node.grantOptionForKw,
node.privileges,
node.onKw,
node.resource,
node.fromKw,
node.roles,
node.grantedBy,
node.behaviorKw,
]),
};
6 changes: 0 additions & 6 deletions test/dcl/grant.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -170,10 +170,4 @@ describe("GRANT", () => {
expect(() => parse("GRANT `role` ON TABLE foo TO 'user:blah'")).toThrowError();
});
});

dialect("postgresql", () => {
it.skip("TODO:postgres", () => {
expect(true).toBe(true);
});
});
});
157 changes: 150 additions & 7 deletions test/dcl/revoke.test.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { dialect, parse, testWc } from "../test_utils";
import { dialect, includeAll, parse, testWc } from "../test_utils";

describe("REVOKE", () => {
dialect("bigquery", () => {
Expand All @@ -21,15 +21,158 @@ describe("REVOKE", () => {
});
});

dialect(["mysql", "mariadb", "sqlite"], () => {
it("does not support REVOKE", () => {
expect(() => parse("REVOKE `role` ON TABLE foo FROM 'user:blah'")).toThrowError();
dialect("postgresql", () => {
[
"SELECT",
"INSERT",
"UPDATE",
"DELETE",
"TRUNCATE",
"REFERENCES",
"TRIGGER",
"MAINTAIN",
].forEach((privilege) => {
it(`supports REVOKE ${privilege} ON TABLE ... FROM role`, () => {
testWc(`REVOKE ${privilege} ON TABLE schm.tbl FROM john_doe`);
});
});

it(`supports revoking multiple privileges`, () => {
testWc(`REVOKE SELECT, UPDATE, INSERT ON TABLE tbl FROM john`);
});

it(`supports REVOKE ALL PRIVILEGES ON TABLE ... FROM role`, () => {
testWc(`REVOKE ALL ON TABLE schm.tbl FROM john_doe`);
testWc(`REVOKE ALL PRIVILEGES ON TABLE schm.tbl FROM john_doe`);
});

it(`supports ALL TABLES IN SCHEMA`, () => {
testWc(`REVOKE INSERT ON ALL TABLES IN SCHEMA my_schema FROM peter_pan`);
testWc(`REVOKE INSERT ON ALL TABLES IN SCHEMA schm1, schm2 FROM peter_pan`);
});

it(`supports multiple tables and roles`, () => {
testWc(`REVOKE UPDATE ON TABLE tbl1, tbl2, tbl3 FROM john_doe, mary_jane`);
});

it(`supports optional TABLE keyword`, () => {
testWc(`REVOKE DELETE ON tbl FROM johnny`);
});

["SELECT", "INSERT", "UPDATE", "REFERENCES"].forEach((privilege) => {
it(`supports REVOKE ${privilege} (cols) ON TABLE ... FROM role`, () => {
testWc(`REVOKE ${privilege} (col1, col2) ON TABLE my_tbl FROM john`);
});
});

it(`supports granting multiple privileges per column`, () => {
testWc(`REVOKE SELECT (col1, col2), UPDATE (col1, col2) ON TABLE my_tbl FROM john`);
});

it(`supports granting all privileges on columns`, () => {
testWc(`REVOKE ALL (col1, col2) ON TABLE my_tbl FROM john`);
testWc(`REVOKE ALL PRIVILEGES (col1) ON TABLE my_tbl FROM john`);
});

["USAGE", "SELECT", "UPDATE"].forEach((privilege) => {
it(`supports REVOKE ${privilege} ON SEQUENCE ... FROM role`, () => {
testWc(`REVOKE ${privilege} ON SEQUENCE schm.seq1, seq2 FROM john_doe`);
});
});

it(`supports ALL SEQUENCES IN SCHEMA`, () => {
testWc(`REVOKE USAGE ON ALL SEQUENCES IN SCHEMA my_schema FROM peter_pan`);
testWc(`REVOKE USAGE, UPDATE ON ALL SEQUENCES IN SCHEMA schm1, schm2 FROM peter_pan`);
});

["CREATE", "CONNECT", "TEMPORARY", "TEMP"].forEach((privilege) => {
it(`supports REVOKE ${privilege} ON DATABASE ... FROM role`, () => {
testWc(`REVOKE ${privilege} ON DATABASE db1, db2 FROM john_doe`);
});
});

it(`supports REVOKE USAGE ON DOMAIN ... FROM role`, () => {
testWc(`REVOKE USAGE ON DOMAIN schm.dom1, dom2 FROM john_doe`);
});

it(`supports REVOKE USAGE ON FOREIGN DATA WRAPPER ... FROM role`, () => {
testWc(`REVOKE USAGE ON FOREIGN DATA WRAPPER wrap1, wrap2 FROM john_doe`);
});

it(`supports REVOKE USAGE ON FOREIGN SERVER ... FROM role`, () => {
testWc(`REVOKE USAGE ON FOREIGN SERVER serv1, serv2 FROM john_doe`);
});

["FUNCTION", "PROCEDURE", "ROUTINE"].forEach((functionKw) => {
it(`supports REVOKE EXECUTE ON ${functionKw} ... FROM role`, () => {
testWc(`REVOKE EXECUTE ON ${functionKw} fibo, fobo FROM john`);
testWc(`REVOKE EXECUTE ON ${functionKw} fn() FROM john`);
testWc(`REVOKE EXECUTE ON ${functionKw} schm.fn (INT, FLOAT) FROM john`);
testWc(`REVOKE EXECUTE ON ${functionKw} fn(a INT, b INT) FROM john`);
testWc(`REVOKE EXECUTE ON ${functionKw} fn(IN a INT, OUT b INT, INOUT c INT) FROM john`);
});
});

["FUNCTIONS", "PROCEDURES", "ROUTINES"].forEach((functionKw) => {
it(`supports REVOKE EXECUTE ON ALL ${functionKw} IN SCHEMA ... FROM role`, () => {
testWc(`REVOKE EXECUTE ON ALL ${functionKw} IN SCHEMA my_schema FROM john`);
testWc(`REVOKE EXECUTE ON ALL ${functionKw} IN SCHEMA schm1, schm2 FROM john`);
});
});

it(`supports REVOKE USAGE ON LANGUAGE ... FROM role`, () => {
testWc(`REVOKE USAGE ON LANGUAGE php, perl FROM script_kiddie`);
});

["SELECT", "UPDATE"].forEach((privilege) => {
it(`supports REVOKE ${privilege} ON LARGE OBJECT ... FROM role`, () => {
testWc(`REVOKE ${privilege} ON LARGE OBJECT 128, 920 FROM john_doe`);
});
});
it(`supports REVOKE ... ON LARGE OBJECT with parameter`, () => {
testWc(`REVOKE UPDATE ON LARGE OBJECT :oid FROM john_doe`, {
...includeAll,
paramTypes: [":name"],
});
});

["SET", "ALTER SYSTEM"].forEach((privilege) => {
it(`supports REVOKE ${privilege} ON PARAMETER ... FROM role`, () => {
testWc(`REVOKE ${privilege} ON PARAMETER foo, bar FROM john_doe`);
});
});

["CREATE", "USAGE"].forEach((privilege) => {
it(`supports REVOKE ${privilege} ON SCHEMA ... FROM role`, () => {
testWc(`REVOKE ${privilege} ON SCHEMA foo, bar FROM john_doe`);
});
});

it(`supports REVOKE CREATE ON TABLESPACE ... FROM role`, () => {
testWc(`REVOKE CREATE ON TABLESPACE spc1, spc2 FROM john_doe`);
});

it(`supports REVOKE USAGE ON TYPE ... FROM role`, () => {
testWc(`REVOKE USAGE ON TYPE schm.typ1, typ2 FROM john_doe`);
});

it(`supports GRANT OPTION FOR clause`, () => {
testWc(`REVOKE GRANT OPTION FOR DELETE ON tbl FROM johnny`);
});

it(`supports GRANTED BY clause`, () => {
testWc(`REVOKE DELETE ON tbl FROM johnny GRANTED BY happy_admin`);
});

it(`supports RESTRICT/CASCADE`, () => {
testWc(`REVOKE DELETE ON tbl FROM johnny RESTRICT`);
testWc(`REVOKE DELETE ON tbl FROM johnny GRANTED BY foo CASCADE`);
});
});

dialect("postgresql", () => {
it.skip("TODO:postgres", () => {
expect(true).toBe(true);
dialect(["mysql", "mariadb", "sqlite"], () => {
it("does not support REVOKE", () => {
expect(() => parse("REVOKE `role` ON TABLE foo FROM 'user:blah'")).toThrowError();
});
});
});

0 comments on commit 424ffca

Please sign in to comment.