From 16af995acb4c0e5fb5981308610a76b7e87c3358 Mon Sep 17 00:00:00 2001 From: Erik Wienhold Date: Sun, 17 Sep 2023 20:54:48 +0200 Subject: [PATCH v1] Fix output of zero privileges in psql Print "(none)" for zero privileges instead of nothing so that the user is able to distinguish zero from default privileges. This affects the following meta commands: \db+ \dD+ \des+ \dew+ \df+ \dL+ \dl+ \dn+ \dp \dT+ \l Default privileges start as NULL::aclitem[] in various catalog columns but revoking the default privileges leaves an empty aclitem array. Using \pset null '(null)' as a workaround to spot default privileges does not work because the meta commands ignore this setting. The privileges shown by \dconfig+ and \ddp as well as the column privileges shown by \dp are not affected by this change because those privileges are reset to NULL instead of leaving empty arrays. Commands \des+ and \dew+ are not covered in src/test/regress because no foreign data wrapper is available at this point to create a foreign server. --- src/bin/psql/describe.c | 6 +- src/test/regress/expected/privileges.out | 93 ++++++++++++++++++++++++ src/test/regress/sql/privileges.sql | 46 ++++++++++++ 3 files changed, 144 insertions(+), 1 deletion(-) diff --git a/src/bin/psql/describe.c b/src/bin/psql/describe.c index bac94a338c..154d244d97 100644 --- a/src/bin/psql/describe.c +++ b/src/bin/psql/describe.c @@ -6718,7 +6718,11 @@ static void printACLColumn(PQExpBuffer buf, const char *colname) { appendPQExpBuffer(buf, - "pg_catalog.array_to_string(%s, E'\\n') AS \"%s\"", + "CASE pg_catalog.cardinality(%s)\n" + " WHEN 0 THEN '%s'\n" + " ELSE pg_catalog.array_to_string(%s, E'\\n')\n" + "END AS \"%s\"", + colname, gettext_noop("(none)"), colname, gettext_noop("Access privileges")); } diff --git a/src/test/regress/expected/privileges.out b/src/test/regress/expected/privileges.out index c1e610e62f..b9eb52f7b1 100644 --- a/src/test/regress/expected/privileges.out +++ b/src/test/regress/expected/privileges.out @@ -2895,3 +2895,96 @@ DROP SCHEMA regress_roleoption; DROP ROLE regress_roleoption_protagonist; DROP ROLE regress_roleoption_donor; DROP ROLE regress_roleoption_recipient; +-- Test zero privileges. +BEGIN; +-- Create an owner for tested objects because output contains owner info. +-- Must be superuser to be owner of tablespace. +CREATE ROLE regress_zeropriv_owner SUPERUSER; +SET LOCAL ROLE regress_zeropriv_owner; +ALTER TABLESPACE regress_tblspace OWNER TO CURRENT_USER; +REVOKE ALL ON TABLESPACE regress_tblspace FROM CURRENT_USER; +\db+ regress_tblspace + List of tablespaces + Name | Owner | Location | Access privileges | Options | Size | Description +------------------+------------------------+-----------------+-------------------+---------+---------+------------- + regress_tblspace | regress_zeropriv_owner | pg_tblspc/16385 | (none) | | 0 bytes | +(1 row) + +CREATE DOMAIN regress_zeropriv_domain AS int; +REVOKE ALL ON DOMAIN regress_zeropriv_domain FROM CURRENT_USER, PUBLIC; +\dD+ regress_zeropriv_domain + List of domains + Schema | Name | Type | Collation | Nullable | Default | Check | Access privileges | Description +--------+-------------------------+---------+-----------+----------+---------+-------+-------------------+------------- + public | regress_zeropriv_domain | integer | | | | | (none) | +(1 row) + +CREATE PROCEDURE regress_zeropriv_proc() LANGUAGE sql AS ''; +REVOKE ALL ON PROCEDURE regress_zeropriv_proc() FROM CURRENT_USER, PUBLIC; +\df+ regress_zeropriv_proc + List of functions + Schema | Name | Result data type | Argument data types | Type | Volatility | Parallel | Owner | Security | Access privileges | Language | Internal name | Description +--------+-----------------------+------------------+---------------------+------+------------+----------+------------------------+----------+-------------------+----------+---------------+------------- + public | regress_zeropriv_proc | | | proc | volatile | unsafe | regress_zeropriv_owner | invoker | (none) | sql | | +(1 row) + +ALTER LANGUAGE plpgsql OWNER TO CURRENT_USER; +REVOKE ALL ON LANGUAGE plpgsql FROM CURRENT_USER, PUBLIC; +\dL+ plpgsql + List of languages + Name | Owner | Trusted | Internal language | Call handler | Validator | Inline handler | Access privileges | Description +---------+------------------------+---------+-------------------+------------------------+------------------------+----------------------------------+-------------------+------------------------------ + plpgsql | regress_zeropriv_owner | t | f | plpgsql_call_handler() | plpgsql_validator(oid) | plpgsql_inline_handler(internal) | (none) | PL/pgSQL procedural language +(1 row) + +SELECT lo_create(3001); + lo_create +----------- + 3001 +(1 row) + +REVOKE ALL ON LARGE OBJECT 3001 FROM CURRENT_USER; +\dl+ + Large objects + ID | Owner | Access privileges | Description +------+------------------------+-------------------+------------- + 3001 | regress_zeropriv_owner | (none) | +(1 row) + +CREATE SCHEMA regress_zeropriv_schema; +REVOKE ALL ON SCHEMA regress_zeropriv_schema FROM CURRENT_USER; +\dn+ regress_zeropriv_schema + List of schemas + Name | Owner | Access privileges | Description +-------------------------+------------------------+-------------------+------------- + regress_zeropriv_schema | regress_zeropriv_owner | (none) | +(1 row) + +CREATE TABLE regress_zeropriv_tbl (a int); +REVOKE ALL ON TABLE regress_zeropriv_tbl FROM CURRENT_USER; +\dp regress_zeropriv_tbl + Access privileges + Schema | Name | Type | Access privileges | Column privileges | Policies +--------+----------------------+-------+-------------------+-------------------+---------- + public | regress_zeropriv_tbl | table | (none) | | +(1 row) + +CREATE TYPE regress_zeropriv_type AS (a int); +REVOKE ALL ON TYPE regress_zeropriv_type FROM CURRENT_USER, PUBLIC; +\dT+ regress_zeropriv_type + List of data types + Schema | Name | Internal name | Size | Elements | Owner | Access privileges | Description +--------+-----------------------+-----------------------+-------+----------+------------------------+-------------------+------------- + public | regress_zeropriv_type | regress_zeropriv_type | tuple | | regress_zeropriv_owner | (none) | +(1 row) + +ALTER DATABASE :"DBNAME" OWNER TO CURRENT_USER; +REVOKE ALL ON DATABASE :"DBNAME" FROM CURRENT_USER, PUBLIC; +\l :"DBNAME" + List of databases + Name | Owner | Encoding | Locale Provider | Collate | Ctype | ICU Locale | ICU Rules | Access privileges +------------+------------------------+-----------+-----------------+---------+-------+------------+-----------+------------------- + regression | regress_zeropriv_owner | SQL_ASCII | libc | C | C | | | (none) +(1 row) + +ROLLBACK; diff --git a/src/test/regress/sql/privileges.sql b/src/test/regress/sql/privileges.sql index bf0035d96d..70c06b2fa4 100644 --- a/src/test/regress/sql/privileges.sql +++ b/src/test/regress/sql/privileges.sql @@ -1861,3 +1861,49 @@ DROP SCHEMA regress_roleoption; DROP ROLE regress_roleoption_protagonist; DROP ROLE regress_roleoption_donor; DROP ROLE regress_roleoption_recipient; + + +-- Test zero privileges. +BEGIN; +-- Create an owner for tested objects because output contains owner info. +-- Must be superuser to be owner of tablespace. +CREATE ROLE regress_zeropriv_owner SUPERUSER; +SET LOCAL ROLE regress_zeropriv_owner; + +ALTER TABLESPACE regress_tblspace OWNER TO CURRENT_USER; +REVOKE ALL ON TABLESPACE regress_tblspace FROM CURRENT_USER; +\db+ regress_tblspace + +CREATE DOMAIN regress_zeropriv_domain AS int; +REVOKE ALL ON DOMAIN regress_zeropriv_domain FROM CURRENT_USER, PUBLIC; +\dD+ regress_zeropriv_domain + +CREATE PROCEDURE regress_zeropriv_proc() LANGUAGE sql AS ''; +REVOKE ALL ON PROCEDURE regress_zeropriv_proc() FROM CURRENT_USER, PUBLIC; +\df+ regress_zeropriv_proc + +ALTER LANGUAGE plpgsql OWNER TO CURRENT_USER; +REVOKE ALL ON LANGUAGE plpgsql FROM CURRENT_USER, PUBLIC; +\dL+ plpgsql + +SELECT lo_create(3001); +REVOKE ALL ON LARGE OBJECT 3001 FROM CURRENT_USER; +\dl+ + +CREATE SCHEMA regress_zeropriv_schema; +REVOKE ALL ON SCHEMA regress_zeropriv_schema FROM CURRENT_USER; +\dn+ regress_zeropriv_schema + +CREATE TABLE regress_zeropriv_tbl (a int); +REVOKE ALL ON TABLE regress_zeropriv_tbl FROM CURRENT_USER; +\dp regress_zeropriv_tbl + +CREATE TYPE regress_zeropriv_type AS (a int); +REVOKE ALL ON TYPE regress_zeropriv_type FROM CURRENT_USER, PUBLIC; +\dT+ regress_zeropriv_type + +ALTER DATABASE :"DBNAME" OWNER TO CURRENT_USER; +REVOKE ALL ON DATABASE :"DBNAME" FROM CURRENT_USER, PUBLIC; +\l :"DBNAME" + +ROLLBACK; -- 2.42.0