mirror of
https://github.com/postgres/postgres.git
synced 2025-12-19 17:02:53 +03:00
psql: Add leakproof indicator to \df+, \do+, \dAo+, and \dC+ output.
This allows users to determine whether particular functions are leakproof, and whether the underlying functions used by operators and casts are leakproof. This is useful to determine whether indexes can be used in queries on security barrier views or tables with row-level security policies. Yugo Nagata, reviewed by Erik Wienhold and Dean Rasheed. Discussion: https://postgr.es/m/20240701220817.483f9b645b95611f8b1f65da%40sranhm.sraoss.co.jp
This commit is contained in:
@@ -304,10 +304,10 @@ describeFunctions(const char *functypes, const char *func_pattern,
|
||||
PQExpBufferData buf;
|
||||
PGresult *res;
|
||||
printQueryOpt myopt = pset.popt;
|
||||
static const bool translate_columns[] = {false, false, false, false, true, true, true, false, true, false, false, false, false};
|
||||
static const bool translate_columns[] = {false, false, false, false, true, true, true, false, true, true, false, false, false, false};
|
||||
|
||||
/* No "Parallel" column before 9.6 */
|
||||
static const bool translate_columns_pre_96[] = {false, false, false, false, true, true, false, true, false, false, false, false};
|
||||
static const bool translate_columns_pre_96[] = {false, false, false, false, true, true, false, true, true, false, false, false, false};
|
||||
|
||||
if (strlen(functypes) != strspn(functypes, "anptwS+"))
|
||||
{
|
||||
@@ -409,11 +409,15 @@ describeFunctions(const char *functypes, const char *func_pattern,
|
||||
gettext_noop("Parallel"));
|
||||
appendPQExpBuffer(&buf,
|
||||
",\n pg_catalog.pg_get_userbyid(p.proowner) as \"%s\""
|
||||
",\n CASE WHEN prosecdef THEN '%s' ELSE '%s' END AS \"%s\"",
|
||||
",\n CASE WHEN prosecdef THEN '%s' ELSE '%s' END AS \"%s\""
|
||||
",\n CASE WHEN p.proleakproof THEN '%s' ELSE '%s' END as \"%s\"",
|
||||
gettext_noop("Owner"),
|
||||
gettext_noop("definer"),
|
||||
gettext_noop("invoker"),
|
||||
gettext_noop("Security"));
|
||||
gettext_noop("Security"),
|
||||
gettext_noop("yes"),
|
||||
gettext_noop("no"),
|
||||
gettext_noop("Leakproof?"));
|
||||
appendPQExpBufferStr(&buf, ",\n ");
|
||||
printACLColumn(&buf, "p.proacl");
|
||||
appendPQExpBuffer(&buf,
|
||||
@@ -792,6 +796,7 @@ describeOperators(const char *oper_pattern,
|
||||
PQExpBufferData buf;
|
||||
PGresult *res;
|
||||
printQueryOpt myopt = pset.popt;
|
||||
static const bool translate_columns[] = {false, false, false, false, false, false, true, false};
|
||||
|
||||
initPQExpBuffer(&buf);
|
||||
|
||||
@@ -825,8 +830,12 @@ describeOperators(const char *oper_pattern,
|
||||
|
||||
if (verbose)
|
||||
appendPQExpBuffer(&buf,
|
||||
" o.oprcode AS \"%s\",\n",
|
||||
gettext_noop("Function"));
|
||||
" o.oprcode AS \"%s\",\n"
|
||||
" CASE WHEN p.proleakproof THEN '%s' ELSE '%s' END AS \"%s\",\n",
|
||||
gettext_noop("Function"),
|
||||
gettext_noop("yes"),
|
||||
gettext_noop("no"),
|
||||
gettext_noop("Leakproof?"));
|
||||
|
||||
appendPQExpBuffer(&buf,
|
||||
" coalesce(pg_catalog.obj_description(o.oid, 'pg_operator'),\n"
|
||||
@@ -851,6 +860,10 @@ describeOperators(const char *oper_pattern,
|
||||
" LEFT JOIN pg_catalog.pg_namespace nt0 ON nt0.oid = t0.typnamespace\n");
|
||||
}
|
||||
|
||||
if (verbose)
|
||||
appendPQExpBufferStr(&buf,
|
||||
" LEFT JOIN pg_catalog.pg_proc p ON p.oid = o.oprcode\n");
|
||||
|
||||
if (!showSystem && !oper_pattern)
|
||||
appendPQExpBufferStr(&buf, "WHERE n.nspname <> 'pg_catalog'\n"
|
||||
" AND n.nspname <> 'information_schema'\n");
|
||||
@@ -908,6 +921,8 @@ describeOperators(const char *oper_pattern,
|
||||
|
||||
myopt.title = _("List of operators");
|
||||
myopt.translate_header = true;
|
||||
myopt.translate_columns = translate_columns;
|
||||
myopt.n_translate_columns = lengthof(translate_columns);
|
||||
|
||||
printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
|
||||
|
||||
@@ -4886,7 +4901,7 @@ listCasts(const char *pattern, bool verbose)
|
||||
PQExpBufferData buf;
|
||||
PGresult *res;
|
||||
printQueryOpt myopt = pset.popt;
|
||||
static const bool translate_columns[] = {false, false, false, true, false};
|
||||
static const bool translate_columns[] = {false, false, false, true, true, false};
|
||||
|
||||
initPQExpBuffer(&buf);
|
||||
|
||||
@@ -4924,7 +4939,13 @@ listCasts(const char *pattern, bool verbose)
|
||||
|
||||
if (verbose)
|
||||
appendPQExpBuffer(&buf,
|
||||
",\n d.description AS \"%s\"",
|
||||
",\n CASE WHEN p.proleakproof THEN '%s'\n"
|
||||
" ELSE '%s'\n"
|
||||
" END AS \"%s\",\n"
|
||||
" d.description AS \"%s\"",
|
||||
gettext_noop("yes"),
|
||||
gettext_noop("no"),
|
||||
gettext_noop("Leakproof?"),
|
||||
gettext_noop("Description"));
|
||||
|
||||
/*
|
||||
@@ -6987,7 +7008,7 @@ listOpFamilyOperators(const char *access_method_pattern,
|
||||
printQueryOpt myopt = pset.popt;
|
||||
bool have_where = false;
|
||||
|
||||
static const bool translate_columns[] = {false, false, false, false, false, false};
|
||||
static const bool translate_columns[] = {false, false, false, false, false, false, true};
|
||||
|
||||
initPQExpBuffer(&buf);
|
||||
|
||||
@@ -7015,8 +7036,15 @@ listOpFamilyOperators(const char *access_method_pattern,
|
||||
|
||||
if (verbose)
|
||||
appendPQExpBuffer(&buf,
|
||||
", ofs.opfname AS \"%s\"\n",
|
||||
gettext_noop("Sort opfamily"));
|
||||
", ofs.opfname AS \"%s\",\n"
|
||||
" CASE\n"
|
||||
" WHEN p.proleakproof THEN '%s'\n"
|
||||
" ELSE '%s'\n"
|
||||
" END AS \"%s\"\n",
|
||||
gettext_noop("Sort opfamily"),
|
||||
gettext_noop("yes"),
|
||||
gettext_noop("no"),
|
||||
gettext_noop("Leakproof?"));
|
||||
appendPQExpBufferStr(&buf,
|
||||
"FROM pg_catalog.pg_amop o\n"
|
||||
" LEFT JOIN pg_catalog.pg_opfamily of ON of.oid = o.amopfamily\n"
|
||||
@@ -7024,7 +7052,9 @@ listOpFamilyOperators(const char *access_method_pattern,
|
||||
" LEFT JOIN pg_catalog.pg_namespace nsf ON of.opfnamespace = nsf.oid\n");
|
||||
if (verbose)
|
||||
appendPQExpBufferStr(&buf,
|
||||
" LEFT JOIN pg_catalog.pg_opfamily ofs ON ofs.oid = o.amopsortfamily\n");
|
||||
" LEFT JOIN pg_catalog.pg_opfamily ofs ON ofs.oid = o.amopsortfamily\n"
|
||||
" LEFT JOIN pg_catalog.pg_operator op ON op.oid = o.amopopr\n"
|
||||
" LEFT JOIN pg_catalog.pg_proc p ON p.oid = op.oprcode\n");
|
||||
|
||||
if (access_method_pattern)
|
||||
{
|
||||
|
||||
@@ -5184,31 +5184,36 @@ List of access methods
|
||||
btree | integer_ops | smallint, integer, bigint
|
||||
(1 row)
|
||||
|
||||
\dAo+ btree float_ops
|
||||
List of operators of operator families
|
||||
AM | Operator family | Operator | Strategy | Purpose | Sort opfamily
|
||||
-------+-----------------+---------------------------------------+----------+---------+---------------
|
||||
btree | float_ops | <(double precision,double precision) | 1 | search |
|
||||
btree | float_ops | <=(double precision,double precision) | 2 | search |
|
||||
btree | float_ops | =(double precision,double precision) | 3 | search |
|
||||
btree | float_ops | >=(double precision,double precision) | 4 | search |
|
||||
btree | float_ops | >(double precision,double precision) | 5 | search |
|
||||
btree | float_ops | <(real,real) | 1 | search |
|
||||
btree | float_ops | <=(real,real) | 2 | search |
|
||||
btree | float_ops | =(real,real) | 3 | search |
|
||||
btree | float_ops | >=(real,real) | 4 | search |
|
||||
btree | float_ops | >(real,real) | 5 | search |
|
||||
btree | float_ops | <(double precision,real) | 1 | search |
|
||||
btree | float_ops | <=(double precision,real) | 2 | search |
|
||||
btree | float_ops | =(double precision,real) | 3 | search |
|
||||
btree | float_ops | >=(double precision,real) | 4 | search |
|
||||
btree | float_ops | >(double precision,real) | 5 | search |
|
||||
btree | float_ops | <(real,double precision) | 1 | search |
|
||||
btree | float_ops | <=(real,double precision) | 2 | search |
|
||||
btree | float_ops | =(real,double precision) | 3 | search |
|
||||
btree | float_ops | >=(real,double precision) | 4 | search |
|
||||
btree | float_ops | >(real,double precision) | 5 | search |
|
||||
(20 rows)
|
||||
\dAo+ btree array_ops|float_ops
|
||||
List of operators of operator families
|
||||
AM | Operator family | Operator | Strategy | Purpose | Sort opfamily | Leakproof?
|
||||
-------+-----------------+---------------------------------------+----------+---------+---------------+------------
|
||||
btree | array_ops | <(anyarray,anyarray) | 1 | search | | no
|
||||
btree | array_ops | <=(anyarray,anyarray) | 2 | search | | no
|
||||
btree | array_ops | =(anyarray,anyarray) | 3 | search | | no
|
||||
btree | array_ops | >=(anyarray,anyarray) | 4 | search | | no
|
||||
btree | array_ops | >(anyarray,anyarray) | 5 | search | | no
|
||||
btree | float_ops | <(double precision,double precision) | 1 | search | | yes
|
||||
btree | float_ops | <=(double precision,double precision) | 2 | search | | yes
|
||||
btree | float_ops | =(double precision,double precision) | 3 | search | | yes
|
||||
btree | float_ops | >=(double precision,double precision) | 4 | search | | yes
|
||||
btree | float_ops | >(double precision,double precision) | 5 | search | | yes
|
||||
btree | float_ops | <(real,real) | 1 | search | | yes
|
||||
btree | float_ops | <=(real,real) | 2 | search | | yes
|
||||
btree | float_ops | =(real,real) | 3 | search | | yes
|
||||
btree | float_ops | >=(real,real) | 4 | search | | yes
|
||||
btree | float_ops | >(real,real) | 5 | search | | yes
|
||||
btree | float_ops | <(double precision,real) | 1 | search | | yes
|
||||
btree | float_ops | <=(double precision,real) | 2 | search | | yes
|
||||
btree | float_ops | =(double precision,real) | 3 | search | | yes
|
||||
btree | float_ops | >=(double precision,real) | 4 | search | | yes
|
||||
btree | float_ops | >(double precision,real) | 5 | search | | yes
|
||||
btree | float_ops | <(real,double precision) | 1 | search | | yes
|
||||
btree | float_ops | <=(real,double precision) | 2 | search | | yes
|
||||
btree | float_ops | =(real,double precision) | 3 | search | | yes
|
||||
btree | float_ops | >=(real,double precision) | 4 | search | | yes
|
||||
btree | float_ops | >(real,double precision) | 5 | search | | yes
|
||||
(25 rows)
|
||||
|
||||
\dAo * pg_catalog.jsonb_path_ops
|
||||
List of operators of operator families
|
||||
@@ -5388,12 +5393,12 @@ create function psql_df_plpgsql ()
|
||||
as $$ begin return; end; $$;
|
||||
comment on function psql_df_plpgsql () is 'some comment';
|
||||
\df+ psql_df_*
|
||||
List of functions
|
||||
Schema | Name | Result data type | Argument data types | Type | Volatility | Parallel | Owner | Security | Access privileges | Language | Internal name | Description
|
||||
--------+------------------+------------------+---------------------+------+------------+----------+-------------------+----------+-------------------+----------+---------------+--------------
|
||||
public | psql_df_internal | double precision | double precision | func | immutable | safe | regress_psql_user | invoker | | internal | dsin |
|
||||
public | psql_df_plpgsql | void | | func | volatile | unsafe | regress_psql_user | invoker | | plpgsql | | some comment
|
||||
public | psql_df_sql | integer | x integer | func | volatile | unsafe | regress_psql_user | definer | | sql | |
|
||||
List of functions
|
||||
Schema | Name | Result data type | Argument data types | Type | Volatility | Parallel | Owner | Security | Leakproof? | Access privileges | Language | Internal name | Description
|
||||
--------+------------------+------------------+---------------------+------+------------+----------+-------------------+----------+------------+-------------------+----------+---------------+--------------
|
||||
public | psql_df_internal | double precision | double precision | func | immutable | safe | regress_psql_user | invoker | no | | internal | dsin |
|
||||
public | psql_df_plpgsql | void | | func | volatile | unsafe | regress_psql_user | invoker | no | | plpgsql | | some comment
|
||||
public | psql_df_sql | integer | x integer | func | volatile | unsafe | regress_psql_user | definer | no | | sql | |
|
||||
(3 rows)
|
||||
|
||||
rollback;
|
||||
@@ -6791,10 +6796,10 @@ REVOKE ALL ON DOMAIN regress_zeropriv_domain FROM CURRENT_USER, PUBLIC;
|
||||
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 | |
|
||||
List of functions
|
||||
Schema | Name | Result data type | Argument data types | Type | Volatility | Parallel | Owner | Security | Leakproof? | Access privileges | Language | Internal name | Description
|
||||
--------+-----------------------+------------------+---------------------+------+------------+----------+------------------------+----------+------------+-------------------+----------+---------------+-------------
|
||||
public | regress_zeropriv_proc | | | proc | volatile | unsafe | regress_zeropriv_owner | invoker | no | (none) | sql | |
|
||||
(1 row)
|
||||
|
||||
CREATE TABLE regress_zeropriv_tbl (a int);
|
||||
|
||||
@@ -1306,7 +1306,7 @@ drop role regress_partitioning_role;
|
||||
\dAc brin pg*.oid*
|
||||
\dAf spgist
|
||||
\dAf btree int4
|
||||
\dAo+ btree float_ops
|
||||
\dAo+ btree array_ops|float_ops
|
||||
\dAo * pg_catalog.jsonb_path_ops
|
||||
\dAp+ btree float_ops
|
||||
\dAp * pg_catalog.uuid_ops
|
||||
|
||||
Reference in New Issue
Block a user