-
Notifications
You must be signed in to change notification settings - Fork 3.8k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
sql/schemachanger: implement DROP OWNED BY
Previously, we did not support the DROP OWNED BY statement (#55381). This commit adds partial support for DROP OWNED BY in the declarative schema changer. Followup work is needed to support checking privileges/roles in the declarative schema changer and to support the CASCADE modifier. Release note: None
- Loading branch information
Jason Chan
committed
Jun 15, 2022
1 parent
aadbaf9
commit eb377e6
Showing
9 changed files
with
352 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,212 @@ | ||
# LogicTest: !local-legacy-schema-changer | ||
|
||
statement ok | ||
CREATE USER testuser2 | ||
|
||
user testuser2 | ||
|
||
statement ok | ||
CREATE TABLE u() | ||
|
||
user testuser | ||
|
||
statement ok | ||
CREATE TABLE t(a INT) | ||
|
||
statement ok | ||
CREATE VIEW v AS SELECT 1 | ||
|
||
query TTTTIT | ||
SHOW TABLES FROM public | ||
---- | ||
public t table testuser 0 NULL | ||
public u table testuser2 0 NULL | ||
public v view testuser 0 NULL | ||
|
||
statement ok | ||
DROP OWNED BY testuser | ||
|
||
query TTTTIT | ||
SHOW TABLES FROM public | ||
---- | ||
public u table testuser2 0 NULL | ||
|
||
query error pgcode 42P01 relation "t" does not exist | ||
SELECT * FROM t | ||
|
||
query error pgcode 42P01 relation "v" does not exist | ||
SELECT * FROM v | ||
|
||
statement ok | ||
CREATE TABLE t1(a INT) | ||
|
||
statement ok | ||
CREATE TABLE t2(b INT) | ||
|
||
statement ok | ||
GRANT SELECT ON t1 TO testuser2 WITH GRANT OPTION | ||
|
||
user testuser2 | ||
|
||
statement ok | ||
CREATE VIEW v1 AS SELECT a FROM t1 | ||
|
||
user testuser | ||
|
||
statement error pq: cannot drop desired object\(s\) because other objects depend on them | ||
DROP OWNED BY testuser | ||
|
||
statement error pq: cannot drop desired object\(s\) because other objects depend on them | ||
DROP OWNED BY testuser RESTRICT | ||
|
||
query TTTTIT | ||
SHOW TABLES FROM public | ||
---- | ||
public t1 table testuser 0 NULL | ||
public t2 table testuser 0 NULL | ||
public u table testuser2 0 NULL | ||
public v1 view testuser2 0 NULL | ||
|
||
user testuser2 | ||
|
||
statement ok | ||
DROP OWNED BY testuser2 | ||
|
||
user testuser | ||
|
||
statement ok | ||
DROP OWNED BY testuser | ||
|
||
query TTTTIT | ||
SHOW TABLES FROM public | ||
---- | ||
|
||
user root | ||
|
||
statement ok | ||
GRANT ALL ON DATABASE test TO testuser WITH GRANT OPTION | ||
|
||
user testuser | ||
|
||
statement ok | ||
CREATE SCHEMA s | ||
|
||
statement ok | ||
CREATE TABLE s.t1() | ||
|
||
statement ok | ||
CREATE TABLE s.t2() | ||
|
||
statement ok | ||
GRANT CREATE ON SCHEMA s TO testuser2 WITH GRANT OPTION | ||
|
||
user testuser2 | ||
|
||
statement ok | ||
CREATE TABLE s.t3() | ||
|
||
user testuser | ||
|
||
statement error pq: cannot drop desired object\(s\) because other objects depend on them | ||
DROP OWNED BY testuser | ||
|
||
user root | ||
|
||
statement ok | ||
GRANT testuser2 TO testuser | ||
|
||
user testuser | ||
|
||
statement ok | ||
DROP OWNED BY testuser, testuser2 | ||
|
||
statement error pq: target database or schema does not exist | ||
SHOW TABLES FROM s | ||
|
||
user root | ||
|
||
statement ok | ||
REVOKE testuser2 FROM testuser | ||
|
||
query TTTB | ||
SHOW GRANTS ON DATABASE test | ||
---- | ||
test admin ALL true | ||
test public CONNECT false | ||
test root ALL true | ||
test testuser ALL true | ||
|
||
statement ok | ||
DROP OWNED BY testuser | ||
|
||
query TTTB | ||
SHOW GRANTS ON DATABASE test | ||
---- | ||
test admin ALL true | ||
test public CONNECT false | ||
test root ALL true | ||
|
||
statement ok | ||
CREATE SCHEMA s | ||
|
||
statement ok | ||
GRANT CREATE ON SCHEMA s TO testuser WITH GRANT OPTION | ||
|
||
user testuser | ||
|
||
statement ok | ||
CREATE TABLE s.t() | ||
|
||
statement ok | ||
DROP OWNED BY testuser | ||
|
||
query TTTTB | ||
SHOW GRANTS ON SCHEMA s | ||
---- | ||
test s admin ALL true | ||
test s root ALL true | ||
|
||
query TTTTIT | ||
SHOW TABLES FROM s | ||
---- | ||
|
||
user root | ||
|
||
statement ok | ||
DROP SCHEMA s | ||
|
||
statement ok | ||
CREATE TABLE t() | ||
|
||
statement ok | ||
GRANT ALL ON t TO testuser WITH GRANT OPTION | ||
|
||
user testuser | ||
|
||
query TTTTTB | ||
SHOW GRANTS ON t | ||
---- | ||
test public t admin ALL true | ||
test public t root ALL true | ||
test public t testuser ALL true | ||
|
||
statement ok | ||
DROP OWNED BY testuser | ||
|
||
query TTTTTB | ||
SHOW GRANTS ON t | ||
---- | ||
test public t admin ALL true | ||
test public t root ALL true | ||
|
||
user root | ||
|
||
statement ok | ||
DROP TABLE t | ||
|
||
user root | ||
statement error pq: cannot drop objects owned by role "root" because they are required by the database system | ||
DROP OWNED BY root | ||
|
||
statement error pq: cannot drop objects owned by role "admin" because they are required by the database system | ||
DROP OWNED BY admin |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
105 changes: 105 additions & 0 deletions
105
pkg/sql/schemachanger/scbuild/internal/scbuildstmt/drop_owned_by.go
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,105 @@ | ||
// Copyright 2022 The Cockroach Authors. | ||
// | ||
// Use of this software is governed by the Business Source License | ||
// included in the file licenses/BSL.txt. | ||
// | ||
// As of the Change Date specified in that file, in accordance with | ||
// the Business Source License, use of this software will be governed | ||
// by the Apache License, Version 2.0, included in the file | ||
// licenses/APL.txt. | ||
|
||
package scbuildstmt | ||
|
||
import ( | ||
"github.com/cockroachdb/cockroach/pkg/security/username" | ||
"github.com/cockroachdb/cockroach/pkg/sql/catalog/descpb" | ||
"github.com/cockroachdb/cockroach/pkg/sql/decodeusername" | ||
"github.com/cockroachdb/cockroach/pkg/sql/pgwire/pgcode" | ||
"github.com/cockroachdb/cockroach/pkg/sql/pgwire/pgerror" | ||
"github.com/cockroachdb/cockroach/pkg/sql/privilege" | ||
"github.com/cockroachdb/cockroach/pkg/sql/schemachanger/scerrors" | ||
"github.com/cockroachdb/cockroach/pkg/sql/schemachanger/scpb" | ||
"github.com/cockroachdb/cockroach/pkg/sql/sem/tree" | ||
) | ||
|
||
// DropOwnedBy implements DROP OWNED BY. | ||
func DropOwnedBy(b BuildCtx, n *tree.DropOwnedBy) { | ||
normalizedRoles, err := decodeusername.FromRoleSpecList( | ||
b.SessionData(), username.PurposeValidation, n.Roles, | ||
) | ||
if err != nil { | ||
panic(err) | ||
} | ||
for _, role := range normalizedRoles { | ||
if role.IsAdminRole() || role.IsRootUser() { | ||
panic(pgerror.Newf(pgcode.DependentObjectsStillExist, | ||
"cannot drop objects owned by role %q because they are required by the database system", role)) | ||
} | ||
// TODO(jasonmchan): check that current user is part of all specified roles | ||
} | ||
|
||
var objects []descpb.ID | ||
var toCheckBackrefs []descpb.ID | ||
|
||
// Lookup all objects in the current database. | ||
_, _, db := scpb.FindDatabase(b.ResolveDatabase(tree.Name(b.SessionData().Database), ResolveParams{ | ||
IsExistenceOptional: false, | ||
RequiredPrivilege: privilege.CONNECT, | ||
})) | ||
dbRefs := undroppedBackrefs(b, db.DatabaseID) | ||
scpb.ForEachSchemaParent(dbRefs, func(_ scpb.Status, _ scpb.TargetStatus, sp *scpb.SchemaParent) { | ||
schemaRefs := undroppedBackrefs(b, sp.SchemaID) | ||
scpb.ForEachObjectParent(schemaRefs, func(_ scpb.Status, _ scpb.TargetStatus, op *scpb.ObjectParent) { | ||
objects = append(objects, op.ObjectID) | ||
}) | ||
objects = append(objects, sp.SchemaID) | ||
}) | ||
|
||
// Drop owned objects and revoke user privileges for the specified roles. | ||
for _, id := range objects { | ||
elts := b.QueryByID(id) | ||
_, _, owner := scpb.FindOwner(elts) | ||
for _, role := range normalizedRoles { | ||
if owner.Owner == role.Normalized() { | ||
if n.DropBehavior == tree.DropCascade { | ||
// TODO(jasonmchan): implement for #55908 | ||
panic(scerrors.NotImplementedError(n)) | ||
} else { | ||
if dropRestrictDescriptor(b, id) { | ||
toCheckBackrefs = append(toCheckBackrefs, id) | ||
} | ||
} | ||
continue | ||
} | ||
scpb.ForEachUserPrivileges(elts, func(_ scpb.Status, _ scpb.TargetStatus, e *scpb.UserPrivileges) { | ||
if e.UserName == role.Normalized() { | ||
dropElement(b, e) | ||
} | ||
}) | ||
} | ||
} | ||
|
||
// Revoke privileges for the database. The current user shouldn't revoke | ||
// their own database privileges. | ||
dbElts := b.QueryByID(db.DatabaseID) | ||
scpb.ForEachUserPrivileges(dbElts, func(_ scpb.Status, _ scpb.TargetStatus, e *scpb.UserPrivileges) { | ||
for _, role := range normalizedRoles { | ||
if e.UserName == role.Normalized() && e.UserName != b.SessionData().User().Normalized() { | ||
dropElement(b, e) | ||
break | ||
} | ||
} | ||
}) | ||
|
||
b.IncrementSubWorkID() | ||
b.IncrementSchemaChangeDropCounter("owned_by") | ||
|
||
// Enforce RESTRICT semantics by checking for backreferences. | ||
for _, id := range toCheckBackrefs { | ||
backrefs := undroppedBackrefs(b, id) | ||
if !backrefs.IsEmpty() { | ||
panic(pgerror.New(pgcode.DependentObjectsStillExist, | ||
"cannot drop desired object(s) because other objects depend on them")) | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.