1
0
mirror of https://github.com/timescale/timescaledb.git synced 2025-05-15 18:13:18 +08:00
timescaledb/test/expected/create_hypertable.out
Erik Nordström 4df8f287a6 Add proper permissions handling for associated (chunk) schemas
A hypertable's associated schema is used to create and store internal
data tables (chunks). A hypertable creates tables in that schema,
typically with full superuser permissions, regardless of whether the
hypertable's owner or the current user have permissions for the schema.
If the schema doesn't exist, the hypertable will create it when
creating the first chunk, even though the user or table owner does
not have permissions to create schemas in the database.

This change adds proper permissions checks to create_hypertable() so
that users cannot create hypertables with a custom associated schema
unless they have the proper permissions on the schema or the database.

Chunks are also no longer created with internal schema permissions if
the associated schema is something different from the internal schema.
2017-12-28 11:24:29 +01:00

280 lines
14 KiB
Plaintext

\c single :ROLE_SUPERUSER
create schema test_schema AUTHORIZATION :ROLE_DEFAULT_PERM_USER;
create schema chunk_schema AUTHORIZATION :ROLE_DEFAULT_PERM_USER_2;
SET ROLE :ROLE_DEFAULT_PERM_USER;
create table test_schema.test_table(time BIGINT, temp float8, device_id text, device_type text, location text, id int, id2 int);
\set ON_ERROR_STOP 0
-- get_create_command should fail since hypertable isn't made yet
SELECT * FROM _timescaledb_internal.get_create_command('test_table');
ERROR: hypertable test_table not found
\set ON_ERROR_STOP 1
\dt "test_schema".*
List of relations
Schema | Name | Type | Owner
-------------+------------+-------+-------------------
test_schema | test_table | table | default_perm_user
(1 row)
create table test_schema.test_table_no_not_null(time BIGINT, device_id text);
\set ON_ERROR_STOP 0
-- Permission denied with unprivileged role
SET ROLE :ROLE_DEFAULT_PERM_USER_2;
select * from create_hypertable('test_schema.test_table_no_not_null', 'time', 'device_id', 2, chunk_time_interval=>_timescaledb_internal.interval_to_usec('1 month'));
ERROR: permission denied for schema test_schema at character 33
-- CREATE on schema is not enough
SET ROLE :ROLE_DEFAULT_PERM_USER;
GRANT ALL ON SCHEMA test_schema TO :ROLE_DEFAULT_PERM_USER_2;
SET ROLE :ROLE_DEFAULT_PERM_USER_2;
select * from create_hypertable('test_schema.test_table_no_not_null', 'time', 'device_id', 2, chunk_time_interval=>_timescaledb_internal.interval_to_usec('1 month'));
ERROR: Permission denied for relation test_schema.test_table_no_not_null
\set ON_ERROR_STOP 1
-- Should work with when granted table owner role
RESET ROLE;
GRANT :ROLE_DEFAULT_PERM_USER TO :ROLE_DEFAULT_PERM_USER_2;
SET ROLE :ROLE_DEFAULT_PERM_USER_2;
select * from create_hypertable('test_schema.test_table_no_not_null', 'time', 'device_id', 2, chunk_time_interval=>_timescaledb_internal.interval_to_usec('1 month'));
NOTICE: Adding NOT NULL constraint to time column time (NULL time values not allowed)
create_hypertable
-------------------
(1 row)
\set ON_ERROR_STOP 0
insert into test_schema.test_table_no_not_null (device_id) VALUES('foo');
ERROR: null value in column "time" violates not-null constraint
\set ON_ERROR_STOP 1
insert into test_schema.test_table_no_not_null (time, device_id) VALUES(1, 'foo');
SELECT * FROM test.show_columns('test_schema.test_table_no_not_null');
Column | Type | Nullable
-----------+--------+----------
time | bigint | t
device_id | text | f
(2 rows)
ALTER TABLE test_schema.test_table_no_not_null ALTER time DROP NOT NULL;
SELECT * FROM test.show_columns('test_schema.test_table_no_not_null');
Column | Type | Nullable
-----------+--------+----------
time | bigint | f
device_id | text | f
(2 rows)
SELECT _timescaledb_internal.set_time_columns_not_null();
set_time_columns_not_null
---------------------------
(1 row)
SELECT * FROM test.show_columns('test_schema.test_table_no_not_null');
Column | Type | Nullable
-----------+--------+----------
time | bigint | t
device_id | text | f
(2 rows)
RESET ROLE;
SET ROLE :ROLE_DEFAULT_PERM_USER;
\set ON_ERROR_STOP 0
-- No permissions on associated schema should fail
select * from create_hypertable('test_schema.test_table', 'time', 'device_id', 2, chunk_time_interval=>_timescaledb_internal.interval_to_usec('1 month'), associated_schema_name => 'chunk_schema');
ERROR: User default_perm_user lacks permissions to create chunks in schema "chunk_schema"
\set ON_ERROR_STOP 1
-- Granting permissions on chunk_schema should make things work
RESET ROLE;
GRANT CREATE ON SCHEMA chunk_schema TO :ROLE_DEFAULT_PERM_USER;
SET ROLE :ROLE_DEFAULT_PERM_USER;
select * from create_hypertable('test_schema.test_table', 'time', 'device_id', 2, chunk_time_interval=>_timescaledb_internal.interval_to_usec('1 month'), associated_schema_name => 'chunk_schema');
NOTICE: Adding NOT NULL constraint to time column time (NULL time values not allowed)
create_hypertable
-------------------
(1 row)
SELECT * FROM _timescaledb_internal.get_create_command('test_table');
get_create_command
----------------------------------------------------------------------------------------------------------------------------------------------------
SELECT create_hypertable('test_schema.test_table', '"time"', 'device_id', 2, chunk_time_interval => 2592000000000, create_default_indexes=>FALSE);
(1 row)
--test adding one more closed dimension
select add_dimension('test_schema.test_table', 'location', 2);
add_dimension
---------------
(1 row)
select * from _timescaledb_catalog.hypertable where table_name = 'test_table';
id | schema_name | table_name | associated_schema_name | associated_table_prefix | num_dimensions
----+-------------+------------+------------------------+-------------------------+----------------
2 | test_schema | test_table | chunk_schema | _hyper_2 | 3
(1 row)
select * from _timescaledb_catalog.dimension;
id | hypertable_id | column_name | column_type | aligned | num_slices | partitioning_func_schema | partitioning_func | interval_length
----+---------------+-------------+-------------+---------+------------+--------------------------+--------------------+-----------------
1 | 1 | time | bigint | t | | | | 2592000000000
2 | 1 | device_id | text | f | 2 | _timescaledb_internal | get_partition_hash |
3 | 2 | time | bigint | t | | | | 2592000000000
4 | 2 | device_id | text | f | 2 | _timescaledb_internal | get_partition_hash |
5 | 2 | location | text | f | 2 | _timescaledb_internal | get_partition_hash |
(5 rows)
\set ON_ERROR_STOP 0
-- get_create_command only works on tables w/ 1 or 2 dimensions
SELECT * FROM _timescaledb_internal.get_create_command('test_table');
ERROR: get_create_command only supports hypertables with up to 2 dimensions
\set ON_ERROR_STOP 1
--test adding one more open dimension
select add_dimension('test_schema.test_table', 'id', interval_length => 1000);
NOTICE: Adding NOT NULL constraint to time column id (NULL time values not allowed)
add_dimension
---------------
(1 row)
select * from _timescaledb_catalog.hypertable where table_name = 'test_table';
id | schema_name | table_name | associated_schema_name | associated_table_prefix | num_dimensions
----+-------------+------------+------------------------+-------------------------+----------------
2 | test_schema | test_table | chunk_schema | _hyper_2 | 4
(1 row)
select * from _timescaledb_catalog.dimension;
id | hypertable_id | column_name | column_type | aligned | num_slices | partitioning_func_schema | partitioning_func | interval_length
----+---------------+-------------+-------------+---------+------------+--------------------------+--------------------+-----------------
1 | 1 | time | bigint | t | | | | 2592000000000
2 | 1 | device_id | text | f | 2 | _timescaledb_internal | get_partition_hash |
3 | 2 | time | bigint | t | | | | 2592000000000
4 | 2 | device_id | text | f | 2 | _timescaledb_internal | get_partition_hash |
5 | 2 | location | text | f | 2 | _timescaledb_internal | get_partition_hash |
6 | 2 | id | integer | t | | | | 1000
(6 rows)
-- Test add_dimension: can use interval types for TIMESTAMPTZ columns
CREATE TABLE dim_test_time(time TIMESTAMPTZ, time2 TIMESTAMPTZ, time3 BIGINT, temp float8, device int, location int);
SELECT create_hypertable('dim_test_time', 'time');
NOTICE: Adding NOT NULL constraint to time column time (NULL time values not allowed)
create_hypertable
-------------------
(1 row)
SELECT add_dimension('dim_test_time', 'time2', interval_length => INTERVAL '1 day');
NOTICE: Adding NOT NULL constraint to time column time2 (NULL time values not allowed)
add_dimension
---------------
(1 row)
-- Test add_dimension: only integral should work on BIGINT columns
\set ON_ERROR_STOP 0
SELECT add_dimension('dim_test_time', 'time3', interval_length => INTERVAL '1 day');
ERROR: interval_length needs to be an integer type for SMALLINT, INTEGER, and BIGINT time columns
-- string is not a valid type
SELECT add_dimension('dim_test_time', 'time3', interval_length => 'foo'::TEXT);
ERROR: interval_length needs to be an integer type for SMALLINT, INTEGER, and BIGINT time columns
\set ON_ERROR_STOP 1
SELECT add_dimension('dim_test_time', 'time3', interval_length => 500);
NOTICE: Adding NOT NULL constraint to time column time3 (NULL time values not allowed)
add_dimension
---------------
(1 row)
-- Test add_dimension: integrals should work on TIMESTAMPTZ columns
CREATE TABLE dim_test_time2(time TIMESTAMPTZ, time2 TIMESTAMPTZ, temp float8, device int, location int);
SELECT create_hypertable('dim_test_time2', 'time');
NOTICE: Adding NOT NULL constraint to time column time (NULL time values not allowed)
create_hypertable
-------------------
(1 row)
SELECT add_dimension('dim_test_time2', 'time2', interval_length => 500);
WARNING: You specified a interval_length of less than a second, make sure that this is what you intended
NOTICE: Adding NOT NULL constraint to time column time2 (NULL time values not allowed)
add_dimension
---------------
(1 row)
\set ON_ERROR_STOP 0
--adding on a non-hypertable
CREATE TABLE not_hypertable(time TIMESTAMPTZ, temp float8, device int, location int);
SELECT add_dimension('not_hypertable', 'time', interval_length => 500);
ERROR: "not_hypertable" is not a hypertable; cannot add dimension
--adding a non-exist column
SELECT add_dimension('test_schema.test_table', 'nope', 2);
ERROR: column "nope" does not exist
--adding the same dimension twice should fail
select add_dimension('test_schema.test_table', 'location', 2);
ERROR: A dimension on column "location" already exists
--adding dimension with both number_partitions and interval_length should fail
select add_dimension('test_schema.test_table', 'id2', number_partitions => 2, interval_length => 1000);
ERROR: Cannot specify both interval and number of slices/partitions for a single dimension
--adding a new dimension on a non-empty table should also fail
insert into test_schema.test_table values (123456789, 23.8, 'blue', 'type1', 'nyc', 1, 1);
select add_dimension('test_schema.test_table', 'device_type', 2);
ERROR: Cannot add new dimension to a non-empty table
\set ON_ERROR_STOP 1
--show chunks in the associated schema
\dt "chunk_schema".*
List of relations
Schema | Name | Type | Owner
--------------+------------------+-------+-------------------
chunk_schema | _hyper_2_2_chunk | table | default_perm_user
(1 row)
--test partitioning in only time dimension
create table test_schema.test_1dim(time timestamp, temp float);
select create_hypertable('test_schema.test_1dim', 'time');
NOTICE: Adding NOT NULL constraint to time column time (NULL time values not allowed)
create_hypertable
-------------------
(1 row)
SELECT * FROM _timescaledb_internal.get_create_command('test_1dim');
get_create_command
-----------------------------------------------------------------------------------------------------------------------------------
SELECT create_hypertable('test_schema.test_1dim', '"time"', chunk_time_interval => 2592000000000, create_default_indexes=>FALSE);
(1 row)
\dt "test_schema".*
List of relations
Schema | Name | Type | Owner
-------------+------------------------+-------+-------------------
test_schema | test_1dim | table | default_perm_user
test_schema | test_table | table | default_perm_user
test_schema | test_table_no_not_null | table | default_perm_user
(3 rows)
select create_hypertable('test_schema.test_1dim', 'time', if_not_exists => true);
NOTICE: hypertable test_schema.test_1dim already exists, skipping
create_hypertable
-------------------
(1 row)
-- Should error when creating again without if_not_exists set to true
\set ON_ERROR_STOP 0
select create_hypertable('test_schema.test_1dim', 'time');
ERROR: hypertable test_schema.test_1dim already exists
\set ON_ERROR_STOP 1
-- if_not_exist should also work with data in the hypertable
insert into test_schema.test_1dim VALUES ('2004-10-19 10:23:54+02', 1.0);
select create_hypertable('test_schema.test_1dim', 'time', if_not_exists => true);
NOTICE: hypertable test_schema.test_1dim already exists, skipping
create_hypertable
-------------------
(1 row)
-- Should error when creating again without if_not_exists set to true
\set ON_ERROR_STOP 0
select create_hypertable('test_schema.test_1dim', 'time');
ERROR: hypertable test_schema.test_1dim already exists
\set ON_ERROR_STOP 1
-- Reset GRANTS
\c single :ROLE_SUPERUSER
REVOKE :ROLE_DEFAULT_PERM_USER FROM :ROLE_DEFAULT_PERM_USER_2;