diff --git a/ir/queries/queries.sql b/ir/queries/queries.sql index 60ec9800..44a31d8b 100644 --- a/ir/queries/queries.sql +++ b/ir/queries/queries.sql @@ -2026,6 +2026,7 @@ WITH acl_data AS ( c.relname::text AS object_name, CASE c.relkind WHEN 'r' THEN 'TABLE' + WHEN 'p' THEN 'TABLE' WHEN 'v' THEN 'VIEW' WHEN 'm' THEN 'VIEW' WHEN 'S' THEN 'SEQUENCE' @@ -2044,7 +2045,7 @@ WITH acl_data AS ( AND dep.refobjsubid = 0 AND dep.deptype = 'e' ) - AND c.relkind IN ('r', 'v', 'm', 'S') + AND c.relkind IN ('r', 'p', 'v', 'm', 'S') AND c.relacl IS NOT NULL -- SERIAL/identity sequences inherit the owning extension table's boundary. AND NOT EXISTS ( @@ -2267,7 +2268,7 @@ WITH column_acls AS ( AND dep.refobjsubid = 0 AND dep.deptype = 'e' ) - AND c.relkind IN ('r', 'v', 'm') -- tables, views, materialized views + AND c.relkind IN ('r', 'p', 'v', 'm') -- ordinary/partitioned tables, views, materialized views AND a.attnum > 0 -- skip system columns AND NOT a.attisdropped AND a.attacl IS NOT NULL -- only columns with explicit ACL diff --git a/ir/queries/queries.sql.go b/ir/queries/queries.sql.go index 2dfc73e3..3707333b 100644 --- a/ir/queries/queries.sql.go +++ b/ir/queries/queries.sql.go @@ -337,7 +337,7 @@ WITH column_acls AS ( AND dep.refobjsubid = 0 AND dep.deptype = 'e' ) - AND c.relkind IN ('r', 'v', 'm') -- tables, views, materialized views + AND c.relkind IN ('r', 'p', 'v', 'm') -- ordinary/partitioned tables, views, materialized views AND a.attnum > 0 -- skip system columns AND NOT a.attisdropped AND a.attacl IS NOT NULL -- only columns with explicit ACL @@ -2601,6 +2601,7 @@ WITH acl_data AS ( c.relname::text AS object_name, CASE c.relkind WHEN 'r' THEN 'TABLE' + WHEN 'p' THEN 'TABLE' WHEN 'v' THEN 'VIEW' WHEN 'm' THEN 'VIEW' WHEN 'S' THEN 'SEQUENCE' @@ -2619,7 +2620,7 @@ WITH acl_data AS ( AND dep.refobjsubid = 0 AND dep.deptype = 'e' ) - AND c.relkind IN ('r', 'v', 'm', 'S') + AND c.relkind IN ('r', 'p', 'v', 'm', 'S') AND c.relacl IS NOT NULL -- SERIAL/identity sequences inherit the owning extension table's boundary. AND NOT EXISTS ( diff --git a/testdata/diff/privilege/issue_640_partitioned_table_grant/diff.sql b/testdata/diff/privilege/issue_640_partitioned_table_grant/diff.sql new file mode 100644 index 00000000..a2f79ee9 --- /dev/null +++ b/testdata/diff/privilege/issue_640_partitioned_table_grant/diff.sql @@ -0,0 +1,5 @@ +REVOKE INSERT ON TABLE events FROM reader; + +GRANT SELECT ON TABLE events TO reader; + +GRANT UPDATE (at) ON TABLE events TO reader; diff --git a/testdata/diff/privilege/issue_640_partitioned_table_grant/new.sql b/testdata/diff/privilege/issue_640_partitioned_table_grant/new.sql new file mode 100644 index 00000000..dffb4df0 --- /dev/null +++ b/testdata/diff/privilege/issue_640_partitioned_table_grant/new.sql @@ -0,0 +1,16 @@ +DO $$ +BEGIN + IF NOT EXISTS (SELECT 1 FROM pg_roles WHERE rolname = 'reader') THEN + CREATE ROLE reader; + END IF; +END $$; + +CREATE TABLE events ( + id int NOT NULL, + at date NOT NULL +) PARTITION BY RANGE (at); + +CREATE TABLE events_2026_01 PARTITION OF events FOR VALUES FROM ('2026-01-01') TO ('2026-02-01'); + +GRANT SELECT ON events TO reader; +GRANT UPDATE (at) ON events TO reader; diff --git a/testdata/diff/privilege/issue_640_partitioned_table_grant/old.sql b/testdata/diff/privilege/issue_640_partitioned_table_grant/old.sql new file mode 100644 index 00000000..be37dcab --- /dev/null +++ b/testdata/diff/privilege/issue_640_partitioned_table_grant/old.sql @@ -0,0 +1,15 @@ +DO $$ +BEGIN + IF NOT EXISTS (SELECT 1 FROM pg_roles WHERE rolname = 'reader') THEN + CREATE ROLE reader; + END IF; +END $$; + +CREATE TABLE events ( + id int NOT NULL, + at date NOT NULL +) PARTITION BY RANGE (at); + +CREATE TABLE events_2026_01 PARTITION OF events FOR VALUES FROM ('2026-01-01') TO ('2026-02-01'); + +GRANT INSERT ON events TO reader; diff --git a/testdata/diff/privilege/issue_640_partitioned_table_grant/plan.json b/testdata/diff/privilege/issue_640_partitioned_table_grant/plan.json new file mode 100644 index 00000000..3feb2e03 --- /dev/null +++ b/testdata/diff/privilege/issue_640_partitioned_table_grant/plan.json @@ -0,0 +1,32 @@ +{ + "version": "1.0.0", + "pgschema_version": "1.13.1", + "created_at": "1970-01-01T00:00:00Z", + "source_fingerprint": { + "hash": "c3d943f90b64cc5a2c206d2e949b575b0f2b0b4d6c2daf9cd3d525764d33eb36" + }, + "groups": [ + { + "steps": [ + { + "sql": "REVOKE INSERT ON TABLE events FROM reader;", + "type": "privilege", + "operation": "alter", + "path": "privileges.TABLE.events.reader" + }, + { + "sql": "GRANT SELECT ON TABLE events TO reader;", + "type": "privilege", + "operation": "alter", + "path": "privileges.TABLE.events.reader" + }, + { + "sql": "GRANT UPDATE (at) ON TABLE events TO reader;", + "type": "column_privilege", + "operation": "create", + "path": "column_privileges.TABLE.events.at.reader" + } + ] + } + ] +} diff --git a/testdata/diff/privilege/issue_640_partitioned_table_grant/plan.sql b/testdata/diff/privilege/issue_640_partitioned_table_grant/plan.sql new file mode 100644 index 00000000..a2f79ee9 --- /dev/null +++ b/testdata/diff/privilege/issue_640_partitioned_table_grant/plan.sql @@ -0,0 +1,5 @@ +REVOKE INSERT ON TABLE events FROM reader; + +GRANT SELECT ON TABLE events TO reader; + +GRANT UPDATE (at) ON TABLE events TO reader; diff --git a/testdata/diff/privilege/issue_640_partitioned_table_grant/plan.txt b/testdata/diff/privilege/issue_640_partitioned_table_grant/plan.txt new file mode 100644 index 00000000..e88315e0 --- /dev/null +++ b/testdata/diff/privilege/issue_640_partitioned_table_grant/plan.txt @@ -0,0 +1,21 @@ +Plan: 1 to add, 2 to modify. + +Summary by type: + privileges: 2 to modify + column privileges: 1 to add + +Privileges: + ~ reader + ~ reader + +Column privileges: + + reader + +DDL to be executed: +-------------------------------------------------- + +REVOKE INSERT ON TABLE events FROM reader; + +GRANT SELECT ON TABLE events TO reader; + +GRANT UPDATE (at) ON TABLE events TO reader;