# LogicTest: !local-legacy-schema-changer
# Skipped on legacy schema changer since it unsupported.

# Test dropping nothing.
statement ok
DROP OWNED BY testuser

statement ok
CREATE USER testuser2

# DROP-OBJECTS: Test that DROP OWNED BY drops objects owned by the specified
# roles.
#
# In this test, testuser creates multiple objects and drops all of them in one
# go. Additionally, testuser2 owns a table that shouldn't be dropped by
# testuser's DROP OWNED BY.
subtest drop-objects

user testuser2

statement ok
CREATE TABLE u()

user root

statement ok
GRANT CREATE ON DATABASE test TO testuser WITH GRANT OPTION

user testuser

statement ok
CREATE TABLE t(a INT)

statement ok
CREATE VIEW v AS SELECT 1

statement ok
CREATE SEQUENCE seq

statement ok
CREATE TYPE enum AS ENUM('a', 'b')

query TTTTIT rowsort
SHOW TABLES FROM public
----
public  seq  sequence  testuser   0  NULL
public  t    table     testuser   0  NULL
public  u    table     testuser2  0  NULL
public  v    view      testuser   0  NULL

query TTTT
SHOW ENUMS
----
public  enum  {a,b}  testuser

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

query TTTT
SHOW ENUMS
----

user testuser2

statement ok
DROP OWNED BY testuser2

query TTTTIT
SHOW TABLES FROM public
----

# DROP-BEHAVIOR-VIEW: Test RESTRICT/CASCADE.
#
# In this test, testuser2 creates a view dependent on a table owned by
# testuser. Under RESTRICT, testuser cannot DROP OWNED BY due to this
# dependency. Under CASCADE, testuser can DROP OWNED BY, which drops both
# testuser's table and testuser2's view.
subtest drop-behavior-view

user testuser

statement ok
CREATE TABLE t(a INT)

statement ok
GRANT SELECT ON t TO testuser2 WITH GRANT OPTION

user testuser2

statement ok
CREATE VIEW v AS SELECT a FROM t

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 rowsort
SHOW TABLES FROM public
----
public  t  table  testuser   0  NULL
public  v  view   testuser2  0  NULL

user root

statement error unimplemented: DROP OWNED BY CASCADE is not yet supported
DROP OWNED BY testuser2 CASCADE

statement ok
DROP OWNED BY testuser, testuser2

query TTTTIT
SHOW TABLES FROM public
----

# DROP-BEHAVIOR-TYPE-1: Test RESTRICT behavior by trying to drop a table
# dependent on a type owned by another role.
subtest drop-behavior-type-1

user root

statement ok
GRANT CREATE ON DATABASE test TO testuser WITH GRANT OPTION

user testuser

statement ok
CREATE TYPE type AS ENUM ('hello')

statement ok
GRANT USAGE ON TYPE type TO testuser2

user testuser2

statement ok
CREATE TABLE t(x type)

user root

statement error pq: cannot drop desired object\(s\) because other objects depend on them
DROP OWNED BY testuser

statement ok
DROP OWNED BY testuser, testuser2

query TTTTIT
SHOW TABLES FROM public
----

query TTT
SHOW TYPES
----

# DROP-BEHAVIOR-TYPE-2: Test RESTRICT behavior by trying to drop a view
# dependent on a type owned by another role.
subtest drop-behavior-type-2

user root

statement ok
GRANT CREATE ON DATABASE test TO testuser WITH GRANT OPTION

user testuser

statement ok
CREATE TYPE type AS ENUM ('hello')

statement ok
GRANT USAGE ON TYPE type TO testuser2

user testuser2

statement ok
CREATE TABLE t(a int)

statement ok
CREATE VIEW v AS SELECT a, 'hello'::type FROM t

user root

statement error pq: cannot drop desired object\(s\) because other objects depend on them
DROP OWNED BY testuser

statement ok
DROP OWNED BY testuser, testuser2

query TTTTIT
SHOW TABLES FROM public
----

query TTT
SHOW TYPES
----

# DROP-SCHEMA: Test that schemas and the objects that they contain can all be
# dropped together by a single DROP OWNED BY (when they are all owned by the
# specified roles).
subtest drop-schema

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
DROP OWNED BY testuser

statement error pq: target database or schema does not exist
SHOW TABLES FROM s

user root

# REVOKE-PRIVILEGES-DB: Test that DROP OWNED BY revokes privileges on the
# current database.
#
# The DROP OWNED BY from the previous subtest did not revoke testuser's
# privileges for the DATABASE. This is because a user should not revoke its own
# database privileges. However, the root user should be able to drop testuser's
# database privileges via DROP OWNED BY.
subtest revoke-privileges-db

query TTTB rowsort
SHOW GRANTS ON DATABASE test
----
test  admin     ALL      true
test  public    CONNECT  false
test  root      ALL      true
test  testuser  ALL      true

user root

statement ok
DROP OWNED BY testuser

query TTTB rowsort
SHOW GRANTS ON DATABASE test
----
test  admin   ALL      true
test  public  CONNECT  false
test  root    ALL      true

# REVOKE-PRIVILEGES-SCHEMA: Test that DROP OWNED BY revokes privileges on
# schemas in the current database.
#
# In this test, root creates a schema and grants privileges for the schema to
# testuser. When testuser issues a DROP OWNED BY, those privileges should be
# revoked.
subtest revoke-privileges-schema

user root

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 rowsort
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

# REVOKE-PRIVILEGES-TABLE: Test that DROP OWNED BY revokes privileges on
# objects in the database.
subtest revoke-privileges-table

user root

statement ok
CREATE TABLE t()

statement ok
GRANT ALL ON t TO testuser WITH GRANT OPTION

user testuser

query TTTTTB rowsort
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 rowsort
SHOW GRANTS ON t
----
test  public  t  admin    ALL  true
test  public  t  root     ALL  true

user root

statement ok
DROP TABLE t

# MUTIROLE: Test DROP OWNED BY with multiple roles.
subtest multirole

statement ok
CREATE ROLE r1

statement ok
CREATE ROLE r2

statement ok
SET ROLE r1

statement ok
CREATE TABLE t1()

statement ok
SET ROLE r2

statement ok
CREATE TABLE t2()

statement ok
SET ROLE root

query TTTTIT rowsort
SHOW TABLES FROM public
----
public  t1  table  r1   0  NULL
public  t2  table  r2   0  NULL

statement ok
DROP OWNED BY r1, r2

query TTTTIT
SHOW TABLES FROM public
----

# ROLES: Test that the current user is a member of all the specified roles. The
# admin role and the root user are off-limits.
subtest roles

user testuser

statement error pq: permission denied to drop objects
DROP OWNED BY testuser2

statement error pq: permission denied to drop objects
DROP OWNED BY testuser, testuser2

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

# KITCHEN-SINK: Test DROP OWNED BY when there are multiple databases/schemas.
# Only objects/privileges in the current database should be dropped.
subtest kitchen-sink

user root

statement ok
CREATE DATABASE d1

statement ok
CREATE DATABASE d2

statement ok
CREATE DATABASE d3

statement ok
CREATE DATABASE d4

statement ok
CREATE SCHEMA d1.s1

statement ok
CREATE SCHEMA d1.s2

statement ok
GRANT CREATE, DROP ON DATABASE d1 TO testuser WITH GRANT OPTION

statement ok
GRANT ALL ON DATABASE d2 TO testuser WITH GRANT OPTION

statement ok
GRANT CREATE ON DATABASE d3 TO testuser WITH GRANT OPTION

statement ok
GRANT CREATE ON SCHEMA d1.s1 TO testuser WITH GRANT OPTION

statement ok
CREATE TABLE d1.t1 (k STRING PRIMARY KEY, v STRING)

statement ok
CREATE VIEW d1.v1 AS SELECT k,v FROM d1.t1

statement ok
CREATE TABLE d1.s1.t1 (a INT)

statement ok
CREATE SCHEMA d2.s1

user testuser

statement ok
CREATE SCHEMA d1.s3

statement ok
CREATE SCHEMA d1.s4

statement ok
CREATE TABLE d1.t2 (k STRING PRIMARY KEY, v STRING)

statement ok
CREATE VIEW d1.v2 AS SELECT k,v FROM d1.t2

statement ok
CREATE TABLE d1.s1.t2 (a INT)

statement ok
CREATE SCHEMA d2.s2

statement ok
CREATE TABLE d2.t1()

user root

query TTTTTT rowsort
SHOW DATABASES
----
d1         root  NULL  NULL  {}  NULL
d2         root  NULL  NULL  {}  NULL
d3         root  NULL  NULL  {}  NULL
d4         root  NULL  NULL  {}  NULL
defaultdb  root  NULL  NULL  {}  NULL
postgres   root  NULL  NULL  {}  NULL
system     node  NULL  NULL  {}  NULL
test       root  NULL  NULL  {}  NULL

statement ok
SET DATABASE = d1

query TT rowsort
SHOW SCHEMAS FROM d1
----
crdb_internal       node
information_schema  node
pg_catalog          node
pg_extension        node
public              root
s1                  root
s2                  root
s3                  testuser
s4                  testuser

query TTTTIT rowsort
SHOW TABLES FROM d1
----
public  t1  table  root      0  NULL
public  t2  table  testuser  0  NULL
public  v1  view   root      0  NULL
public  v2  view   testuser  0  NULL
s1      t1  table  root      0  NULL
s1      t2  table  testuser  0  NULL

query TTTB rowsort
SHOW GRANTS ON DATABASE d1
----
d1  admin     ALL      true
d1  public    CONNECT  false
d1  root      ALL      true
d1  testuser  CREATE   true
d1  testuser  DROP     true

query TTTTB rowsort
SHOW GRANTS ON SCHEMA d1.s1
----
d1  s1  admin     ALL     true
d1  s1  root      ALL     true
d1  s1  testuser  CREATE  true

statement ok
DROP OWNED BY testuser

query TT rowsort
SHOW SCHEMAS FROM d1
----
crdb_internal       node
information_schema  node
pg_catalog          node
pg_extension        node
public              root
s1                  root
s2                  root

query TTTTIT rowsort
SHOW TABLES FROM d1
----
public  t1  table  root      0  NULL
public  v1  view   root      0  NULL
s1      t1  table  root      0  NULL

query TTTTB rowsort
SHOW GRANTS ON SCHEMA d1.s1
----
d1  s1  admin     ALL     true
d1  s1  root      ALL     true

query TTTB rowsort
SHOW GRANTS ON DATABASE d1
----
d1  admin     ALL      true
d1  public    CONNECT  false
d1  root      ALL      true

statement ok
SET DATABASE = d2

query TT rowsort
SHOW SCHEMAS FROM d2
----
crdb_internal       node
information_schema  node
pg_catalog          node
pg_extension        node
public              root
s1                  root
s2                  testuser

query TTTTIT
SHOW TABLES FROM d2
----
public  t1  table  testuser  0  NULL

query TTTB rowsort
SHOW GRANTS ON DATABASE d2
----
d2  admin     ALL      true
d2  public    CONNECT  false
d2  root      ALL      true
d2  testuser  ALL      true

statement ok
DROP OWNED BY testuser

query TT rowsort
SHOW SCHEMAS FROM d2
----
crdb_internal       node
information_schema  node
pg_catalog          node
pg_extension        node
public              root
s1                  root

query TTTTIT
SHOW TABLES FROM d2
----

query TTTB rowsort
SHOW GRANTS ON DATABASE d2
----
d2  admin     ALL      true
d2  public    CONNECT  false
d2  root      ALL      true

statement ok
SET DATABASE = d3

query TTTB rowsort
SHOW GRANTS ON DATABASE d3
----
d3  admin     ALL      true
d3  public    CONNECT  false
d3  root      ALL      true
d3  testuser  CREATE   true

statement ok
DROP OWNED BY testuser

query TTTB rowsort
SHOW GRANTS ON DATABASE d3
----
d3  admin   ALL      true
d3  public  CONNECT  false
d3  root    ALL      true

# Drop owned by should not work if the user has synthetic privileges.

statement ok
GRANT SYSTEM MODIFYCLUSTERSETTING TO testuser

statement error pq: cannot perform drop owned by if role has synthetic privileges; testuser has entries in system.privileges
DROP OWNED BY testuser

subtest drop_function

statement ok
CREATE USER u_drop_udf;

statement ok
CREATE FUNCTION f_drop_udf() RETURNS INT LANGUAGE SQL AS $$ SELECT 1 $$;

statement ok
ALTER FUNCTION f_drop_udf OWNER TO u_drop_udf;

statement ok
DROP OWNED BY u_drop_udf;

statement error pq: unknown function: f_drop_udf\(\)
SHOW CREATE FUNCTION f_drop_udf;
