Skip to content

Commit

Permalink
Use separate repair function
Browse files Browse the repository at this point in the history
Instead of having the repair in the latest-dev, this creates repair
function and uses it in the post-update script.
  • Loading branch information
mkindahl committed Nov 8, 2023
1 parent cac77cb commit 9ea558d
Show file tree
Hide file tree
Showing 9 changed files with 188 additions and 38 deletions.
40 changes: 40 additions & 0 deletions sql/maintenance_utils.sql
Original file line number Diff line number Diff line change
Expand Up @@ -117,3 +117,43 @@ BEGIN
END CASE;
END
$$ LANGUAGE plpgsql;

-- A version of makeaclitem that accepts a comma-separated list of
-- privileges rather than just a single privilege. This is copied from
-- PG16, but since we need to support earlier versions, we provide it
-- with the extension.
--
-- This is intended for internal usage and interface might change.
CREATE FUNCTION _timescaledb_functions.makeaclitem(regrole, regrole, text, bool)
RETURNS AclItem AS '@MODULE_PATHNAME@', 'ts_makeaclitem'
LANGUAGE C STABLE PARALLEL SAFE;

-- Repair relation ACL by removing roles that do not exist in pg_authid.
CREATE PROCEDURE _timescaledb_functions.repair_relation_acls()
LANGUAGE SQL AS $$
WITH
badrels AS (
SELECT oid::regclass
FROM (SELECT oid, (aclexplode(relacl)).* FROM pg_class) AS rels
WHERE rels.grantee != 0
AND rels.grantee NOT IN (SELECT oid FROM pg_authid)
),
pickacls AS (
SELECT oid::regclass,
_timescaledb_functions.makeaclitem(
b.grantee,
b.grantor,
string_agg(b.privilege_type, ','),
b.is_grantable
) AS acl
FROM (SELECT oid, (aclexplode(relacl)).* AS a FROM pg_class) AS b
WHERE b.grantee IN (SELECT oid FROM pg_authid)
GROUP BY oid, b.grantee, b.grantor, b.is_grantable
),
cleanacls AS (
SELECT oid, array_agg(acl) AS acl FROM pickacls GROUP BY oid
)
UPDATE pg_class c
SET relacl = (SELECT acl FROM cleanacls n WHERE c.oid = n.oid)
WHERE oid IN (SELECT oid FROM badrels)
$$ SET search_path TO pg_catalog, pg_temp;
38 changes: 0 additions & 38 deletions sql/updates/latest-dev.sql
Original file line number Diff line number Diff line change
Expand Up @@ -250,41 +250,3 @@ CREATE FUNCTION @[email protected]_chunks(
created_after "any" = NULL
) RETURNS SETOF REGCLASS AS '@MODULE_PATHNAME@', 'ts_chunk_show_chunks'
LANGUAGE C STABLE PARALLEL SAFE;

-- A version of makeaclitem that accepts a comma-separated list of
-- privileges rather than just a single privilege. This is copied from
-- PG16, but since we need to support earlier versions, we provide it
-- with the extension.
CREATE FUNCTION _timescaledb_functions.makeaclitem(regrole, regrole, text, bool)
RETURNS AclItem AS '@MODULE_PATHNAME@', 'ts_makeaclitem'
LANGUAGE C STABLE PARALLEL SAFE;

-- Repair relations that have relacl entries for users that do not exist in pg_authid
WITH
badrels AS (
SELECT oid::regclass
FROM (SELECT oid, (aclexplode(relacl)).* FROM pg_catalog.pg_class) AS rels
WHERE rels.grantee != 0
AND rels.grantee NOT IN (SELECT oid FROM pg_catalog.pg_authid)
),
pickacls AS (
SELECT oid::regclass,
_timescaledb_functions.makeaclitem(
b.grantee,
b.grantor,
string_agg(b.privilege_type, ','),
b.is_grantable
) AS acl
FROM (SELECT oid, (aclexplode(relacl)).* AS a FROM pg_catalog.pg_class) AS b
WHERE b.grantee IN (SELECT oid FROM pg_catalog.pg_authid)
GROUP BY oid, b.grantee, b.grantor, b.is_grantable
),
cleanacls AS (
SELECT oid, array_agg(acl) AS acl FROM pickacls GROUP BY oid
)
UPDATE pg_catalog.pg_class c
SET relacl = (SELECT acl FROM cleanacls n WHERE c.oid = n.oid)
WHERE oid IN (SELECT oid FROM badrels);

DROP FUNCTION _timescaledb_functions.makeaclitem(regrole, regrole, text, bool);

3 changes: 3 additions & 0 deletions sql/updates/post-update.sql
Original file line number Diff line number Diff line change
Expand Up @@ -194,3 +194,6 @@ BEGIN
END;
$$;

-- Repair relations that have relacl entries for users that do not
-- exist in pg_authid
CALL _timescaledb_functions.repair_relation_acls();
3 changes: 3 additions & 0 deletions sql/updates/reverse-dev.sql
Original file line number Diff line number Diff line change
Expand Up @@ -191,3 +191,6 @@ CREATE FUNCTION @[email protected]_chunks(
newer_than "any" = NULL
) RETURNS SETOF REGCLASS AS '@MODULE_PATHNAME@', 'ts_chunk_show_chunks'
LANGUAGE C STABLE PARALLEL SAFE;

DROP FUNCTION IF EXISTS _timescaledb_functions.repair_relation_acls();
DROP FUNCTION IF EXISTS _timescaledb_functions.makeaclitem(regrole, regrole, text, bool);
4 changes: 4 additions & 0 deletions src/utils.c
Original file line number Diff line number Diff line change
Expand Up @@ -1436,6 +1436,10 @@ convert_any_priv_string(text *priv_type_text, const priv_map *privileges)
return result;
}

/*
* This is copied from PostgreSQL 16.0 since versions before 16.0 does not
* support lists for privileges but we need that.
*/
Datum
ts_makeaclitem(PG_FUNCTION_ARGS)
{
Expand Down
74 changes: 74 additions & 0 deletions test/expected/repair.out
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
-- This file and its contents are licensed under the Apache License 2.0.
-- Please see the included NOTICE for copyright information and
-- LICENSE-APACHE for a copy of the license.
-- We are testing different repair functions here to make sure that
-- they work as expected.
\c :TEST_DBNAME :ROLE_SUPERUSER
CREATE USER wizard;
CREATE USER "Random L User";
CREATE TABLE test_table_1(time timestamptz not null, temp float);
SELECT create_hypertable('test_table_1', by_range('time', '1 day'::interval));
create_hypertable
-------------------
(1,t)
(1 row)

INSERT INTO test_table_1(time,temp)
SELECT time, 100 * random()
FROM generate_series(
'2000-01-01'::timestamptz,
'2000-01-05'::timestamptz,
'1min'::interval
) time;
CREATE TABLE test_table_2(time timestamptz not null, temp float);
SELECT create_hypertable('test_table_2', by_range('time', '1 day'::interval));
create_hypertable
-------------------
(2,t)
(1 row)

INSERT INTO test_table_2(time,temp)
SELECT time, 100 * random()
FROM generate_series(
'2000-01-01'::timestamptz,
'2000-01-05'::timestamptz,
'1min'::interval
) time;
GRANT ALL ON test_table_1 TO wizard;
GRANT ALL ON test_table_2 TO wizard;
GRANT SELECT, INSERT ON test_table_1 TO "Random L User";
GRANT INSERT ON test_table_2 TO "Random L User";
-- Break the relacl of the table by deleting users
DELETE FROM pg_authid WHERE rolname IN ('wizard', 'Random L User');
CREATE TABLE saved (LIKE pg_class);
INSERT INTO saved SELECT * FROM pg_class;
CALL _timescaledb_functions.repair_relation_acls();
-- The only thing we should see here are the relations we broke and
-- the privileges we added for that user. No other relations should be
-- touched.
WITH
lhs AS (SELECT oid, aclexplode(relacl) FROM pg_class),
rhs AS (SELECT oid, aclexplode(relacl) FROM saved)
SELECT rhs.oid::regclass
FROM lhs FULL OUTER JOIN rhs ON row(lhs) = row(rhs)
WHERE lhs.oid IS NULL AND rhs.oid IS NOT NULL
GROUP BY rhs.oid;
oid
-----------------------------------------
test_table_1
_timescaledb_internal._hyper_1_1_chunk
_timescaledb_internal._hyper_1_2_chunk
_timescaledb_internal._hyper_1_3_chunk
_timescaledb_internal._hyper_1_4_chunk
_timescaledb_internal._hyper_1_5_chunk
test_table_2
_timescaledb_internal._hyper_2_6_chunk
_timescaledb_internal._hyper_2_7_chunk
_timescaledb_internal._hyper_2_8_chunk
_timescaledb_internal._hyper_2_9_chunk
_timescaledb_internal._hyper_2_10_chunk
(12 rows)

DROP TABLE saved;
DROP TABLE test_table_1;
DROP TABLE test_table_2;
1 change: 1 addition & 0 deletions test/sql/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ set(TEST_FILES
plan_hypertable_inline.sql
relocate_extension.sql
reloptions.sql
repair.sql
size_utils.sql
sort_optimization.sql
sql_query.sql
Expand Down
61 changes: 61 additions & 0 deletions test/sql/repair.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
-- This file and its contents are licensed under the Apache License 2.0.
-- Please see the included NOTICE for copyright information and
-- LICENSE-APACHE for a copy of the license.

-- We are testing different repair functions here to make sure that
-- they work as expected.

\c :TEST_DBNAME :ROLE_SUPERUSER

CREATE USER wizard;
CREATE USER "Random L User";

CREATE TABLE test_table_1(time timestamptz not null, temp float);
SELECT create_hypertable('test_table_1', by_range('time', '1 day'::interval));

INSERT INTO test_table_1(time,temp)
SELECT time, 100 * random()
FROM generate_series(
'2000-01-01'::timestamptz,
'2000-01-05'::timestamptz,
'1min'::interval
) time;

CREATE TABLE test_table_2(time timestamptz not null, temp float);
SELECT create_hypertable('test_table_2', by_range('time', '1 day'::interval));

INSERT INTO test_table_2(time,temp)
SELECT time, 100 * random()
FROM generate_series(
'2000-01-01'::timestamptz,
'2000-01-05'::timestamptz,
'1min'::interval
) time;

GRANT ALL ON test_table_1 TO wizard;
GRANT ALL ON test_table_2 TO wizard;
GRANT SELECT, INSERT ON test_table_1 TO "Random L User";
GRANT INSERT ON test_table_2 TO "Random L User";

-- Break the relacl of the table by deleting users
DELETE FROM pg_authid WHERE rolname IN ('wizard', 'Random L User');

CREATE TABLE saved (LIKE pg_class);
INSERT INTO saved SELECT * FROM pg_class;

CALL _timescaledb_functions.repair_relation_acls();

-- The only thing we should see here are the relations we broke and
-- the privileges we added for that user. No other relations should be
-- touched.
WITH
lhs AS (SELECT oid, aclexplode(relacl) FROM pg_class),
rhs AS (SELECT oid, aclexplode(relacl) FROM saved)
SELECT rhs.oid::regclass
FROM lhs FULL OUTER JOIN rhs ON row(lhs) = row(rhs)
WHERE lhs.oid IS NULL AND rhs.oid IS NOT NULL
GROUP BY rhs.oid;

DROP TABLE saved;
DROP TABLE test_table_1;
DROP TABLE test_table_2;
2 changes: 2 additions & 0 deletions tsl/test/shared/expected/extension.out
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,7 @@ ORDER BY pronamespace::regnamespace::text COLLATE "C", p.oid::regprocedure::text
_timescaledb_functions.invalidation_process_hypertable_log(integer,integer,regtype,integer[],bigint[],bigint[],text[])
_timescaledb_functions.last_combinefunc(internal,internal)
_timescaledb_functions.last_sfunc(internal,anyelement,"any")
_timescaledb_functions.makeaclitem(regrole,regrole,text,boolean)
_timescaledb_functions.materialization_invalidation_log_delete(integer)
_timescaledb_functions.partialize_agg(anyelement)
_timescaledb_functions.ping_data_node(name,interval)
Expand All @@ -127,6 +128,7 @@ ORDER BY pronamespace::regnamespace::text COLLATE "C", p.oid::regprocedure::text
_timescaledb_functions.recompress_chunk_segmentwise(regclass,boolean)
_timescaledb_functions.relation_size(regclass)
_timescaledb_functions.remote_txn_heal_data_node(oid)
_timescaledb_functions.repair_relation_acls()
_timescaledb_functions.restart_background_workers()
_timescaledb_functions.rxid_in(cstring)
_timescaledb_functions.rxid_out(rxid)
Expand Down

0 comments on commit 9ea558d

Please sign in to comment.