mirror of
https://github.com/timescale/timescaledb.git
synced 2025-05-15 18:13:18 +08:00
The materialised hypertable resides in the _timescaledb.internal schema which resulted in permission error at the time of manual index creation by non super user. To solve this, it now switches to timescaledb user before index creation of CAgg. Fixes #4735
266 lines
10 KiB
PL/PgSQL
266 lines
10 KiB
PL/PgSQL
-- This file and its contents are licensed under the Timescale License.
|
|
-- Please see the included NOTICE for copyright information and
|
|
-- LICENSE-TIMESCALE for a copy of the license.
|
|
|
|
-- initialize the bgw mock state to prevent the materialization workers from running
|
|
\c :TEST_DBNAME :ROLE_SUPERUSER
|
|
|
|
-- remove any default jobs, e.g., telemetry so bgw_job isn't polluted
|
|
DELETE FROM _timescaledb_config.bgw_job WHERE TRUE;
|
|
|
|
CREATE VIEW cagg_info AS
|
|
WITH
|
|
caggs AS (
|
|
SELECT format('%I.%I', user_view_schema, user_view_name)::regclass AS user_view,
|
|
format('%I.%I', direct_view_schema, direct_view_name)::regclass AS direct_view,
|
|
format('%I.%I', partial_view_schema, partial_view_name)::regclass AS partial_view,
|
|
format('%I.%I', ht.schema_name, ht.table_name)::regclass AS mat_relid
|
|
FROM _timescaledb_catalog.hypertable ht,
|
|
_timescaledb_catalog.continuous_agg cagg
|
|
WHERE ht.id = cagg.mat_hypertable_id
|
|
)
|
|
SELECT user_view,
|
|
(SELECT relacl FROM pg_class WHERE oid = user_view) AS user_view_perm,
|
|
relname AS mat_table,
|
|
(relacl) AS mat_table_perm,
|
|
direct_view,
|
|
(SELECT relacl FROM pg_class WHERE oid = direct_view) AS direct_view_perm,
|
|
partial_view,
|
|
(SELECT relacl FROM pg_class WHERE oid = partial_view) AS partial_view_perm
|
|
FROM pg_class JOIN caggs ON pg_class.oid = caggs.mat_relid;
|
|
GRANT SELECT ON cagg_info TO PUBLIC;
|
|
|
|
\c :TEST_DBNAME :ROLE_DEFAULT_PERM_USER
|
|
|
|
CREATE TABLE conditions (
|
|
timec INT NOT NULL,
|
|
location TEXT NOT NULL,
|
|
temperature DOUBLE PRECISION NULL,
|
|
humidity DOUBLE PRECISION NULL,
|
|
lowp double precision NULL,
|
|
highp double precision null,
|
|
allnull double precision null
|
|
);
|
|
|
|
select table_name from create_hypertable( 'conditions', 'timec', chunk_time_interval=> 100);
|
|
CREATE OR REPLACE FUNCTION integer_now_test1() returns int LANGUAGE SQL STABLE as $$ SELECT coalesce(max(timec), 0) FROM conditions $$;
|
|
SELECT set_integer_now_func('conditions', 'integer_now_test1');
|
|
|
|
|
|
CREATE MATERIALIZED VIEW mat_refresh_test
|
|
WITH (timescaledb.continuous)
|
|
as
|
|
select location, max(humidity)
|
|
from conditions
|
|
group by time_bucket(100, timec), location WITH NO DATA;
|
|
|
|
-- Manually create index on CAgg
|
|
CREATE INDEX cagg_idx on mat_refresh_test(location);
|
|
\c :TEST_DBNAME :ROLE_SUPERUSER
|
|
CREATE USER not_priv;
|
|
\c :TEST_DBNAME not_priv
|
|
-- A user with no ownership on the Cagg cannot create index on it. -- This should fail
|
|
\set ON_ERROR_STOP 0
|
|
CREATE INDEX cagg_idx on mat_refresh_test(humidity);
|
|
\c :TEST_DBNAME :ROLE_SUPERUSER
|
|
DROP USER not_priv;
|
|
\c :TEST_DBNAME :ROLE_DEFAULT_PERM_USER
|
|
|
|
SELECT add_continuous_aggregate_policy('mat_refresh_test', NULL, -200::integer, '12 h'::interval);
|
|
|
|
insert into conditions
|
|
select generate_series(0, 50, 10), 'NYC', 55, 75, 40, 70, NULL;
|
|
|
|
CALL refresh_continuous_aggregate(' mat_refresh_test', NULL, NULL);
|
|
|
|
SELECT id as cagg_job_id FROM _timescaledb_config.bgw_job order by id desc limit 1 \gset
|
|
SELECT format('%I.%I', materialization_hypertable_schema, materialization_hypertable_name ) as materialization_hypertable
|
|
FROM timescaledb_information.continuous_aggregates
|
|
WHERE view_name = 'mat_refresh_test' \gset
|
|
|
|
SELECT mat_hypertable_id FROM _timescaledb_catalog.continuous_agg WHERE user_view_name = 'mat_refresh_test' \gset
|
|
|
|
SELECT schema_name as mat_chunk_schema, table_name as mat_chunk_table
|
|
FROM _timescaledb_catalog.chunk
|
|
WHERE hypertable_id = :mat_hypertable_id
|
|
ORDER BY id desc
|
|
LIMIT 1 \gset
|
|
|
|
CREATE TABLE conditions_for_perm_check (
|
|
timec INT NOT NULL,
|
|
location TEXT NOT NULL,
|
|
temperature DOUBLE PRECISION NULL,
|
|
humidity DOUBLE PRECISION NULL,
|
|
lowp double precision NULL,
|
|
highp double precision null,
|
|
allnull double precision null
|
|
);
|
|
|
|
select table_name from create_hypertable('conditions_for_perm_check', 'timec', chunk_time_interval=> 100);
|
|
CREATE OR REPLACE FUNCTION integer_now_test2() returns int LANGUAGE SQL STABLE as $$ SELECT coalesce(max(timec), 0) FROM conditions_for_perm_check $$;
|
|
SELECT set_integer_now_func('conditions_for_perm_check', 'integer_now_test2');
|
|
|
|
CREATE TABLE conditions_for_perm_check_w_grant (
|
|
timec INT NOT NULL,
|
|
location TEXT NOT NULL,
|
|
temperature DOUBLE PRECISION NULL,
|
|
humidity DOUBLE PRECISION NULL,
|
|
lowp double precision NULL,
|
|
highp double precision null,
|
|
allnull double precision null
|
|
);
|
|
|
|
select table_name from create_hypertable('conditions_for_perm_check_w_grant', 'timec', chunk_time_interval=> 100);
|
|
CREATE OR REPLACE FUNCTION integer_now_test3() returns int LANGUAGE SQL STABLE as $$ SELECT coalesce(max(timec), 0) FROM conditions_for_perm_check_w_grant $$;
|
|
SELECT set_integer_now_func('conditions_for_perm_check_w_grant', 'integer_now_test3');
|
|
|
|
GRANT SELECT, TRIGGER ON conditions_for_perm_check_w_grant TO public;
|
|
|
|
insert into conditions_for_perm_check_w_grant
|
|
select generate_series(0, 30, 10), 'POR', 55, 75, 40, 70, NULL;
|
|
|
|
--need both select and trigger permissions to create a materialized view on top of it.
|
|
GRANT SELECT, TRIGGER ON conditions_for_perm_check_w_grant TO public;
|
|
|
|
\c :TEST_DBNAME :ROLE_SUPERUSER
|
|
|
|
create schema custom_schema;
|
|
|
|
CREATE FUNCTION get_constant() RETURNS INTEGER LANGUAGE SQL IMMUTABLE AS
|
|
$BODY$
|
|
SELECT 10;
|
|
$BODY$;
|
|
|
|
REVOKE EXECUTE ON FUNCTION get_constant() FROM PUBLIC;
|
|
|
|
\c :TEST_DBNAME :ROLE_DEFAULT_PERM_USER_2
|
|
\set ON_ERROR_STOP 0
|
|
select from alter_job(:cagg_job_id, max_runtime => NULL);
|
|
|
|
--make sure that commands fail
|
|
|
|
ALTER MATERIALIZED VIEW mat_refresh_test SET(timescaledb.materialized_only = true);
|
|
DROP MATERIALIZED VIEW mat_refresh_test;
|
|
CALL refresh_continuous_aggregate('mat_refresh_test', NULL, NULL);
|
|
|
|
SELECT * FROM mat_refresh_test;
|
|
SELECT * FROM :materialization_hypertable;
|
|
SELECT * FROM :"mat_chunk_schema".:"mat_chunk_table";
|
|
|
|
--cannot create a mat view without select and trigger grants
|
|
CREATE MATERIALIZED VIEW mat_perm_view_test
|
|
WITH (timescaledb.continuous, timescaledb.materialized_only=true)
|
|
as
|
|
select location, max(humidity)
|
|
from conditions_for_perm_check
|
|
group by time_bucket(100, timec), location WITH NO DATA;
|
|
|
|
--cannot create mat view in a schema without create privileges
|
|
CREATE MATERIALIZED VIEW custom_schema.mat_perm_view_test
|
|
WITH (timescaledb.continuous, timescaledb.materialized_only=true)
|
|
as
|
|
select location, max(humidity)
|
|
from conditions_for_perm_check_w_grant
|
|
group by time_bucket(100, timec), location WITH NO DATA;
|
|
|
|
--cannot use a function without EXECUTE privileges
|
|
--you can create a VIEW but cannot refresh it
|
|
CREATE MATERIALIZED VIEW mat_perm_view_test
|
|
WITH ( timescaledb.continuous, timescaledb.materialized_only=true)
|
|
as
|
|
select location, max(humidity), get_constant()
|
|
from conditions_for_perm_check_w_grant
|
|
group by time_bucket(100, timec), location WITH NO DATA;
|
|
|
|
--this should fail
|
|
CALL refresh_continuous_aggregate('mat_perm_view_test', NULL, NULL);
|
|
DROP MATERIALIZED VIEW mat_perm_view_test;
|
|
|
|
--can create a mat view on something with select and trigger grants
|
|
CREATE MATERIALIZED VIEW mat_perm_view_test
|
|
WITH ( timescaledb.continuous, timescaledb.materialized_only=true)
|
|
as
|
|
select location, max(humidity)
|
|
from conditions_for_perm_check_w_grant
|
|
group by time_bucket(100, timec), location WITH NO DATA;
|
|
|
|
CALL refresh_continuous_aggregate('mat_perm_view_test', NULL, NULL);
|
|
SELECT * FROM mat_perm_view_test;
|
|
|
|
\c :TEST_DBNAME :ROLE_DEFAULT_PERM_USER
|
|
--revoke select permissions from role with mat view
|
|
REVOKE SELECT ON conditions_for_perm_check_w_grant FROM public;
|
|
|
|
insert into conditions_for_perm_check_w_grant
|
|
select generate_series(100, 130, 10), 'POR', 65, 85, 30, 90, NULL;
|
|
|
|
\c :TEST_DBNAME :ROLE_DEFAULT_PERM_USER_2
|
|
--refresh mat view should now fail due to lack of permissions
|
|
CALL refresh_continuous_aggregate('mat_perm_view_test', NULL, NULL);
|
|
|
|
--but the old data will still be there
|
|
SELECT * FROM mat_perm_view_test;
|
|
|
|
\set VERBOSITY default
|
|
|
|
-- Test that grants and revokes are propagated to the implementation
|
|
-- objects, that is, the user view, the partial view, the direct view,
|
|
-- and the materialization table.
|
|
\c :TEST_DBNAME :ROLE_DEFAULT_PERM_USER
|
|
CREATE TABLE devices (
|
|
time TIMESTAMPTZ NOT NULL,
|
|
device INT,
|
|
temp DOUBLE PRECISION NULL,
|
|
PRIMARY KEY(time, device)
|
|
);
|
|
|
|
SELECT create_hypertable('devices', 'time');
|
|
GRANT SELECT, TRIGGER ON devices TO :ROLE_DEFAULT_PERM_USER_2;
|
|
|
|
INSERT INTO devices
|
|
SELECT time, (random() * 30)::int, random() * 80
|
|
FROM generate_series('2020-02-01 00:00:00'::timestamptz, '2020-03-01 00:00:00', '1 hour') AS time;
|
|
|
|
\c :TEST_DBNAME :ROLE_DEFAULT_PERM_USER_2
|
|
|
|
CREATE MATERIALIZED VIEW devices_summary
|
|
WITH (timescaledb.continuous, timescaledb.materialized_only=true)
|
|
AS SELECT time_bucket('1 day', time) AS bucket, device, MAX(temp)
|
|
FROM devices GROUP BY bucket, device WITH NO DATA;
|
|
|
|
\x on
|
|
SELECT * FROM cagg_info WHERE user_view::text = 'devices_summary';
|
|
GRANT ALL ON devices_summary TO :ROLE_DEFAULT_PERM_USER;
|
|
SELECT * FROM cagg_info WHERE user_view::text = 'devices_summary';
|
|
REVOKE SELECT, UPDATE ON devices_summary FROM :ROLE_DEFAULT_PERM_USER;
|
|
SELECT * FROM cagg_info WHERE user_view::text = 'devices_summary';
|
|
\x off
|
|
|
|
-- Check for default privilege permissions get propagated to the materialization hypertable
|
|
\c :TEST_DBNAME :ROLE_SUPERUSER
|
|
CREATE SCHEMA test_default_privileges;
|
|
GRANT USAGE ON SCHEMA "test_default_privileges" TO :ROLE_DEFAULT_PERM_USER;
|
|
ALTER DEFAULT PRIVILEGES IN SCHEMA "test_default_privileges" GRANT SELECT ON TABLES TO :ROLE_DEFAULT_PERM_USER;
|
|
|
|
CREATE TABLE test_default_privileges.devices (
|
|
time TIMESTAMPTZ NOT NULL,
|
|
device INT,
|
|
temp DOUBLE PRECISION NULL,
|
|
PRIMARY KEY(time, device)
|
|
);
|
|
|
|
SELECT create_hypertable('test_default_privileges.devices', 'time');
|
|
|
|
CREATE MATERIALIZED VIEW test_default_privileges.devices_summary
|
|
WITH (timescaledb.continuous)
|
|
AS
|
|
SELECT time_bucket('1 day', time) AS bucket, device, MAX(temp)
|
|
FROM test_default_privileges.devices
|
|
GROUP BY bucket, device
|
|
WITH NO DATA;
|
|
|
|
-- check if user view perms have been propagated to the mat-ht
|
|
SELECT user_view_perm IS NOT DISTINCT FROM mat_table_perm
|
|
FROM cagg_info
|
|
WHERE user_view = 'test_default_privileges.devices_summary'::regclass;
|