Skip to content

Commit

Permalink
Allow anyone to use size utilities on distributed hypertables
Browse files Browse the repository at this point in the history
This change removes a check for `USAGE` privileges on data nodes
required to query the data node using utility commands, such as
`hypertable_size`. Normally, PostgreSQL doesn't require `USAGE` on a
foreign server to query its remote tables. Also, size utilities, like
`pg_table_size` can be used by anyone---even roles without any
privileges on a table. The behavior on distributed hypertables is now
consistent with PostgreSQL.

Fixes #3698
  • Loading branch information
erimatnor committed Oct 15, 2021
1 parent cb13754 commit 5f60a29
Show file tree
Hide file tree
Showing 4 changed files with 171 additions and 7 deletions.
12 changes: 8 additions & 4 deletions tsl/src/data_node.c
Original file line number Diff line number Diff line change
Expand Up @@ -1577,12 +1577,16 @@ data_node_name_list_check_acl(List *data_node_names, AclMode mode)

foreach (lc, data_node_names)
{
/* Validate the servers, but privilege check is optional */
ForeignServer *server = GetForeignServerByName(lfirst(lc), false);

/* Must have permissions on the server object */
aclresult = pg_foreign_server_aclcheck(server->serverid, curuserid, mode);
if (mode != ACL_NO_CHECK)
{
/* Must have permissions on the server object */
aclresult = pg_foreign_server_aclcheck(server->serverid, curuserid, mode);

if (aclresult != ACLCHECK_OK)
aclcheck_error(aclresult, OBJECT_FOREIGN_SERVER, server->servername);
if (aclresult != ACLCHECK_OK)
aclcheck_error(aclresult, OBJECT_FOREIGN_SERVER, server->servername);
}
}
}
6 changes: 3 additions & 3 deletions tsl/src/remote/dist_commands.c
Original file line number Diff line number Diff line change
Expand Up @@ -97,11 +97,11 @@ ts_dist_cmd_params_invoke_on_data_nodes(const char *sql, StmtParams *params, Lis
switch (nodeTag(data_nodes))
{
case T_OidList:
data_nodes = data_node_oids_to_node_name_list(data_nodes, ACL_USAGE);
data_nodes = data_node_oids_to_node_name_list(data_nodes, ACL_NO_CHECK);
break;
case T_List:
/* Already in the format we want. Just check permissions. */
data_node_name_list_check_acl(data_nodes, ACL_USAGE);
/* Already in the format we want */
data_node_name_list_check_acl(data_nodes, ACL_NO_CHECK);
break;
default:
elog(ERROR, "invalid list type %u", nodeTag(data_nodes));
Expand Down
124 changes: 124 additions & 0 deletions tsl/test/expected/dist_util.out
Original file line number Diff line number Diff line change
Expand Up @@ -843,6 +843,130 @@ SELECT * FROM hypertable_index_size('nondisttable_pkey');
40960
(1 row)

-- Make sure functions work for non-superuser
CREATE TABLE size_test_table (value int);
INSERT INTO size_test_table SELECT * FROM generate_series(0, 10000);
SET ROLE :ROLE_1;
-- No query permissions
\set ON_ERROR_STOP 0
SELECT count(*) FROM disttable;
ERROR: permission denied for table disttable
SELECT count(*) FROM size_test_table;
ERROR: permission denied for table size_test_table
\set ON_ERROR_STOP 1
-- Size functions work anyway, similar to pg_table_size, et al.
-- pg_table_size() can vary with platform so not outputting
SELECT 1 FROM pg_table_size('size_test_table');
?column?
----------
1
(1 row)

SELECT 1 FROM pg_table_size('disttable');
?column?
----------
1
(1 row)

SELECT 1 FROM pg_table_size('nondisttable');
?column?
----------
1
(1 row)

SELECT * FROM hypertable_size('disttable');
hypertable_size
-----------------
131072
(1 row)

SELECT * FROM hypertable_size('nondisttable');
hypertable_size
-----------------
114688
(1 row)

SELECT * FROM hypertable_detailed_size('disttable') ORDER BY node_name;
table_bytes | index_bytes | toast_bytes | total_bytes | node_name
-------------+-------------+-------------+-------------+-------------
16384 | 49152 | 8192 | 73728 | data_node_1
8192 | 32768 | 8192 | 49152 | data_node_2
0 | 8192 | 0 | 8192 |
(3 rows)

SELECT * FROM hypertable_detailed_size('nondisttable') ORDER BY node_name;
table_bytes | index_bytes | toast_bytes | total_bytes | node_name
-------------+-------------+-------------+-------------+-----------
24576 | 73728 | 16384 | 114688 |
(1 row)

SELECT * FROM chunks_detailed_size('disttable') ORDER BY chunk_schema, chunk_name, node_name;
chunk_schema | chunk_name | table_bytes | index_bytes | toast_bytes | total_bytes | node_name
-----------------------+-----------------------+-------------+-------------+-------------+-------------+-------------
_timescaledb_internal | _dist_hyper_2_2_chunk | 8192 | 24576 | 8192 | 40960 | data_node_1
_timescaledb_internal | _dist_hyper_2_5_chunk | 8192 | 24576 | 8192 | 40960 | data_node_2
_timescaledb_internal | _dist_hyper_2_6_chunk | 8192 | 16384 | 0 | 24576 | data_node_1
(3 rows)

SELECT * FROM chunks_detailed_size('nondisttable') ORDER BY chunk_schema, chunk_name, node_name;
chunk_schema | chunk_name | table_bytes | index_bytes | toast_bytes | total_bytes | node_name
-----------------------+------------------+-------------+-------------+-------------+-------------+-----------
_timescaledb_internal | _hyper_1_1_chunk | 8192 | 24576 | 8192 | 40960 |
_timescaledb_internal | _hyper_1_3_chunk | 8192 | 24576 | 8192 | 40960 |
_timescaledb_internal | _hyper_1_4_chunk | 8192 | 16384 | 0 | 24576 |
(3 rows)

SELECT * FROM hypertable_compression_stats('disttable') ORDER BY node_name;
total_chunks | number_compressed_chunks | before_compression_table_bytes | before_compression_index_bytes | before_compression_toast_bytes | before_compression_total_bytes | after_compression_table_bytes | after_compression_index_bytes | after_compression_toast_bytes | after_compression_total_bytes | node_name
--------------+--------------------------+--------------------------------+--------------------------------+--------------------------------+--------------------------------+-------------------------------+-------------------------------+-------------------------------+-------------------------------+-------------
2 | 1 | 8192 | 16384 | 0 | 24576 | 8192 | 16384 | 8192 | 32768 | data_node_1
1 | 1 | 8192 | 16384 | 0 | 24576 | 8192 | 16384 | 8192 | 32768 | data_node_2
(2 rows)

SELECT * FROM hypertable_compression_stats('nondisttable') ORDER BY node_name;
total_chunks | number_compressed_chunks | before_compression_table_bytes | before_compression_index_bytes | before_compression_toast_bytes | before_compression_total_bytes | after_compression_table_bytes | after_compression_index_bytes | after_compression_toast_bytes | after_compression_total_bytes | node_name
--------------+--------------------------+--------------------------------+--------------------------------+--------------------------------+--------------------------------+-------------------------------+-------------------------------+-------------------------------+-------------------------------+-----------
3 | 2 | 16384 | 32768 | 0 | 49152 | 16384 | 32768 | 16384 | 65536 |
(1 row)

SELECT * FROM chunk_compression_stats('disttable') ORDER BY chunk_schema, chunk_name, node_name;
chunk_schema | chunk_name | compression_status | before_compression_table_bytes | before_compression_index_bytes | before_compression_toast_bytes | before_compression_total_bytes | after_compression_table_bytes | after_compression_index_bytes | after_compression_toast_bytes | after_compression_total_bytes | node_name
-----------------------+-----------------------+--------------------+--------------------------------+--------------------------------+--------------------------------+--------------------------------+-------------------------------+-------------------------------+-------------------------------+-------------------------------+-------------
_timescaledb_internal | _dist_hyper_2_2_chunk | Compressed | 8192 | 16384 | 0 | 24576 | 8192 | 16384 | 8192 | 32768 | data_node_1
_timescaledb_internal | _dist_hyper_2_5_chunk | Compressed | 8192 | 16384 | 0 | 24576 | 8192 | 16384 | 8192 | 32768 | data_node_2
_timescaledb_internal | _dist_hyper_2_6_chunk | Uncompressed | | | | | | | | | data_node_1
(3 rows)

SELECT * FROM chunk_compression_stats('nondisttable') ORDER BY chunk_schema, chunk_name, node_name;
chunk_schema | chunk_name | compression_status | before_compression_table_bytes | before_compression_index_bytes | before_compression_toast_bytes | before_compression_total_bytes | after_compression_table_bytes | after_compression_index_bytes | after_compression_toast_bytes | after_compression_total_bytes | node_name
-----------------------+------------------+--------------------+--------------------------------+--------------------------------+--------------------------------+--------------------------------+-------------------------------+-------------------------------+-------------------------------+-------------------------------+-----------
_timescaledb_internal | _hyper_1_1_chunk | Compressed | 8192 | 16384 | 0 | 24576 | 8192 | 16384 | 8192 | 32768 |
_timescaledb_internal | _hyper_1_3_chunk | Compressed | 8192 | 16384 | 0 | 24576 | 8192 | 16384 | 8192 | 32768 |
_timescaledb_internal | _hyper_1_4_chunk | Uncompressed | | | | | | | | |
(3 rows)

SELECT * FROM hypertable_index_size('disttable_pkey');
hypertable_index_size
-----------------------
57344
(1 row)

SELECT * FROM hypertable_index_size('nondisttable_pkey');
hypertable_index_size
-----------------------
40960
(1 row)

RESET ROLE;
GRANT SELECT ON disttable TO :ROLE_1;
SET ROLE :ROLE_1;
-- Querying should now work
SELECT count(*) FROM disttable;
count
-------
5
(1 row)

-- Make sure timescaledb.ssl_dir and passfile gucs can be read by a non-superuser
\c :TEST_DBNAME :ROLE_1
\unset ECHO
Expand Down
36 changes: 36 additions & 0 deletions tsl/test/sql/dist_util.sql
Original file line number Diff line number Diff line change
Expand Up @@ -278,6 +278,42 @@ SELECT * FROM chunk_compression_stats('nondisttable') ORDER BY chunk_schema, chu
SELECT * FROM hypertable_index_size('disttable_pkey');
SELECT * FROM hypertable_index_size('nondisttable_pkey');

-- Make sure functions work for non-superuser
CREATE TABLE size_test_table (value int);
INSERT INTO size_test_table SELECT * FROM generate_series(0, 10000);

SET ROLE :ROLE_1;

-- No query permissions
\set ON_ERROR_STOP 0
SELECT count(*) FROM disttable;
SELECT count(*) FROM size_test_table;
\set ON_ERROR_STOP 1

-- Size functions work anyway, similar to pg_table_size, et al.
-- pg_table_size() can vary with platform so not outputting
SELECT 1 FROM pg_table_size('size_test_table');
SELECT 1 FROM pg_table_size('disttable');
SELECT 1 FROM pg_table_size('nondisttable');
SELECT * FROM hypertable_size('disttable');
SELECT * FROM hypertable_size('nondisttable');
SELECT * FROM hypertable_detailed_size('disttable') ORDER BY node_name;
SELECT * FROM hypertable_detailed_size('nondisttable') ORDER BY node_name;
SELECT * FROM chunks_detailed_size('disttable') ORDER BY chunk_schema, chunk_name, node_name;
SELECT * FROM chunks_detailed_size('nondisttable') ORDER BY chunk_schema, chunk_name, node_name;
SELECT * FROM hypertable_compression_stats('disttable') ORDER BY node_name;
SELECT * FROM hypertable_compression_stats('nondisttable') ORDER BY node_name;
SELECT * FROM chunk_compression_stats('disttable') ORDER BY chunk_schema, chunk_name, node_name;
SELECT * FROM chunk_compression_stats('nondisttable') ORDER BY chunk_schema, chunk_name, node_name;
SELECT * FROM hypertable_index_size('disttable_pkey');
SELECT * FROM hypertable_index_size('nondisttable_pkey');

RESET ROLE;
GRANT SELECT ON disttable TO :ROLE_1;
SET ROLE :ROLE_1;
-- Querying should now work
SELECT count(*) FROM disttable;

-- Make sure timescaledb.ssl_dir and passfile gucs can be read by a non-superuser
\c :TEST_DBNAME :ROLE_1
\unset ECHO
Expand Down

0 comments on commit 5f60a29

Please sign in to comment.