mirror of
https://github.com/postgres/postgres.git
synced 2025-05-03 22:24:49 +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:
parent
af8cd1639a
commit
2355e51110
@ -729,6 +729,9 @@ EXPLAIN (ANALYZE, TIMING OFF, BUFFERS OFF) SELECT * FROM t WHERE a <= 49 AND
|
|||||||
accurately, the function that the operator is based on). If not, then the
|
accurately, the function that the operator is based on). If not, then the
|
||||||
selectivity estimator will behave as if no statistics are available, and
|
selectivity estimator will behave as if no statistics are available, and
|
||||||
the planner will proceed with default or fall-back assumptions.
|
the planner will proceed with default or fall-back assumptions.
|
||||||
|
The <xref linkend="app-psql"/> program's
|
||||||
|
<command><link linkend="app-psql-meta-command-do-lc">\do+</link></command>
|
||||||
|
meta-command is useful to determine which operators are marked as leakproof.
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
|
@ -1420,7 +1420,8 @@ SELECT $1 \parse stmt1
|
|||||||
is specified, only members of operator families whose names match that
|
is specified, only members of operator families whose names match that
|
||||||
pattern are listed.
|
pattern are listed.
|
||||||
If <literal>+</literal> is appended to the command name, each operator
|
If <literal>+</literal> is appended to the command name, each operator
|
||||||
is listed with its sort operator family (if it is an ordering operator).
|
is listed with its sort operator family (if it is an ordering operator),
|
||||||
|
and whether its underlying function is leakproof.
|
||||||
</para>
|
</para>
|
||||||
</listitem>
|
</listitem>
|
||||||
</varlistentry>
|
</varlistentry>
|
||||||
@ -1509,8 +1510,9 @@ SELECT $1 \parse stmt1
|
|||||||
If <replaceable class="parameter">pattern</replaceable>
|
If <replaceable class="parameter">pattern</replaceable>
|
||||||
is specified, only casts whose source or target types match the
|
is specified, only casts whose source or target types match the
|
||||||
pattern are listed.
|
pattern are listed.
|
||||||
If <literal>+</literal> is appended to the command name, each object
|
If <literal>+</literal> is appended to the command name, additional
|
||||||
is listed with its associated description.
|
information about each cast is shown, including whether its underlying
|
||||||
|
function is leakproof, and the cast's description.
|
||||||
</para>
|
</para>
|
||||||
</listitem>
|
</listitem>
|
||||||
</varlistentry>
|
</varlistentry>
|
||||||
@ -1711,9 +1713,9 @@ SELECT $1 \parse stmt1
|
|||||||
modifier to include system objects.
|
modifier to include system objects.
|
||||||
If the form <literal>\df+</literal> is used, additional information
|
If the form <literal>\df+</literal> is used, additional information
|
||||||
about each function is shown, including volatility,
|
about each function is shown, including volatility,
|
||||||
parallel safety, owner, security classification, access privileges,
|
parallel safety, owner, security classification, whether it is
|
||||||
language, internal name (for C and internal functions only),
|
leakproof, access privileges, language, internal name (for C and
|
||||||
and description.
|
internal functions only), and description.
|
||||||
Source code for a specific function can be seen
|
Source code for a specific function can be seen
|
||||||
using <literal>\sf</literal>.
|
using <literal>\sf</literal>.
|
||||||
</para>
|
</para>
|
||||||
@ -1862,8 +1864,8 @@ SELECT $1 \parse stmt1
|
|||||||
pattern or the <literal>S</literal> modifier to include system
|
pattern or the <literal>S</literal> modifier to include system
|
||||||
objects.
|
objects.
|
||||||
If <literal>+</literal> is appended to the command name,
|
If <literal>+</literal> is appended to the command name,
|
||||||
additional information about each operator is shown, currently just
|
additional information about each operator is shown, including
|
||||||
the name of the underlying function.
|
the name of the underlying function, and whether it is leakproof.
|
||||||
</para>
|
</para>
|
||||||
</listitem>
|
</listitem>
|
||||||
</varlistentry>
|
</varlistentry>
|
||||||
|
@ -2167,6 +2167,17 @@ CREATE VIEW phone_number WITH (security_barrier) AS
|
|||||||
view's row filters.
|
view's row filters.
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
For example, an index scan cannot be selected for queries on security
|
||||||
|
barrier views (or tables with row-level security policies) if an
|
||||||
|
operator used in the <literal>WHERE</literal> clause is associated with the
|
||||||
|
operator family of the index, but its underlying function is not marked
|
||||||
|
<literal>LEAKPROOF</literal>. The <xref linkend="app-psql"/> program's
|
||||||
|
<command><link linkend="app-psql-meta-command-dao">\dAo+</link></command>
|
||||||
|
meta-command is useful to list operator families and determine which of
|
||||||
|
their operators are marked as leakproof.
|
||||||
|
</para>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
It is important to understand that even a view created with the
|
It is important to understand that even a view created with the
|
||||||
<literal>security_barrier</literal> option is intended to be secure only
|
<literal>security_barrier</literal> option is intended to be secure only
|
||||||
|
@ -304,10 +304,10 @@ describeFunctions(const char *functypes, const char *func_pattern,
|
|||||||
PQExpBufferData buf;
|
PQExpBufferData buf;
|
||||||
PGresult *res;
|
PGresult *res;
|
||||||
printQueryOpt myopt = pset.popt;
|
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 */
|
/* 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+"))
|
if (strlen(functypes) != strspn(functypes, "anptwS+"))
|
||||||
{
|
{
|
||||||
@ -409,11 +409,15 @@ describeFunctions(const char *functypes, const char *func_pattern,
|
|||||||
gettext_noop("Parallel"));
|
gettext_noop("Parallel"));
|
||||||
appendPQExpBuffer(&buf,
|
appendPQExpBuffer(&buf,
|
||||||
",\n pg_catalog.pg_get_userbyid(p.proowner) as \"%s\""
|
",\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("Owner"),
|
||||||
gettext_noop("definer"),
|
gettext_noop("definer"),
|
||||||
gettext_noop("invoker"),
|
gettext_noop("invoker"),
|
||||||
gettext_noop("Security"));
|
gettext_noop("Security"),
|
||||||
|
gettext_noop("yes"),
|
||||||
|
gettext_noop("no"),
|
||||||
|
gettext_noop("Leakproof?"));
|
||||||
appendPQExpBufferStr(&buf, ",\n ");
|
appendPQExpBufferStr(&buf, ",\n ");
|
||||||
printACLColumn(&buf, "p.proacl");
|
printACLColumn(&buf, "p.proacl");
|
||||||
appendPQExpBuffer(&buf,
|
appendPQExpBuffer(&buf,
|
||||||
@ -792,6 +796,7 @@ describeOperators(const char *oper_pattern,
|
|||||||
PQExpBufferData buf;
|
PQExpBufferData buf;
|
||||||
PGresult *res;
|
PGresult *res;
|
||||||
printQueryOpt myopt = pset.popt;
|
printQueryOpt myopt = pset.popt;
|
||||||
|
static const bool translate_columns[] = {false, false, false, false, false, false, true, false};
|
||||||
|
|
||||||
initPQExpBuffer(&buf);
|
initPQExpBuffer(&buf);
|
||||||
|
|
||||||
@ -825,8 +830,12 @@ describeOperators(const char *oper_pattern,
|
|||||||
|
|
||||||
if (verbose)
|
if (verbose)
|
||||||
appendPQExpBuffer(&buf,
|
appendPQExpBuffer(&buf,
|
||||||
" o.oprcode AS \"%s\",\n",
|
" o.oprcode AS \"%s\",\n"
|
||||||
gettext_noop("Function"));
|
" 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,
|
appendPQExpBuffer(&buf,
|
||||||
" coalesce(pg_catalog.obj_description(o.oid, 'pg_operator'),\n"
|
" 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");
|
" 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)
|
if (!showSystem && !oper_pattern)
|
||||||
appendPQExpBufferStr(&buf, "WHERE n.nspname <> 'pg_catalog'\n"
|
appendPQExpBufferStr(&buf, "WHERE n.nspname <> 'pg_catalog'\n"
|
||||||
" AND n.nspname <> 'information_schema'\n");
|
" AND n.nspname <> 'information_schema'\n");
|
||||||
@ -908,6 +921,8 @@ describeOperators(const char *oper_pattern,
|
|||||||
|
|
||||||
myopt.title = _("List of operators");
|
myopt.title = _("List of operators");
|
||||||
myopt.translate_header = true;
|
myopt.translate_header = true;
|
||||||
|
myopt.translate_columns = translate_columns;
|
||||||
|
myopt.n_translate_columns = lengthof(translate_columns);
|
||||||
|
|
||||||
printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
|
printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
|
||||||
|
|
||||||
@ -4886,7 +4901,7 @@ listCasts(const char *pattern, bool verbose)
|
|||||||
PQExpBufferData buf;
|
PQExpBufferData buf;
|
||||||
PGresult *res;
|
PGresult *res;
|
||||||
printQueryOpt myopt = pset.popt;
|
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);
|
initPQExpBuffer(&buf);
|
||||||
|
|
||||||
@ -4924,7 +4939,13 @@ listCasts(const char *pattern, bool verbose)
|
|||||||
|
|
||||||
if (verbose)
|
if (verbose)
|
||||||
appendPQExpBuffer(&buf,
|
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"));
|
gettext_noop("Description"));
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -6987,7 +7008,7 @@ listOpFamilyOperators(const char *access_method_pattern,
|
|||||||
printQueryOpt myopt = pset.popt;
|
printQueryOpt myopt = pset.popt;
|
||||||
bool have_where = false;
|
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);
|
initPQExpBuffer(&buf);
|
||||||
|
|
||||||
@ -7015,8 +7036,15 @@ listOpFamilyOperators(const char *access_method_pattern,
|
|||||||
|
|
||||||
if (verbose)
|
if (verbose)
|
||||||
appendPQExpBuffer(&buf,
|
appendPQExpBuffer(&buf,
|
||||||
", ofs.opfname AS \"%s\"\n",
|
", ofs.opfname AS \"%s\",\n"
|
||||||
gettext_noop("Sort opfamily"));
|
" 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,
|
appendPQExpBufferStr(&buf,
|
||||||
"FROM pg_catalog.pg_amop o\n"
|
"FROM pg_catalog.pg_amop o\n"
|
||||||
" LEFT JOIN pg_catalog.pg_opfamily of ON of.oid = o.amopfamily\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");
|
" LEFT JOIN pg_catalog.pg_namespace nsf ON of.opfnamespace = nsf.oid\n");
|
||||||
if (verbose)
|
if (verbose)
|
||||||
appendPQExpBufferStr(&buf,
|
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)
|
if (access_method_pattern)
|
||||||
{
|
{
|
||||||
|
@ -5184,31 +5184,36 @@ List of access methods
|
|||||||
btree | integer_ops | smallint, integer, bigint
|
btree | integer_ops | smallint, integer, bigint
|
||||||
(1 row)
|
(1 row)
|
||||||
|
|
||||||
\dAo+ btree float_ops
|
\dAo+ btree array_ops|float_ops
|
||||||
List of operators of operator families
|
List of operators of operator families
|
||||||
AM | Operator family | Operator | Strategy | Purpose | Sort opfamily
|
AM | Operator family | Operator | Strategy | Purpose | Sort opfamily | Leakproof?
|
||||||
-------+-----------------+---------------------------------------+----------+---------+---------------
|
-------+-----------------+---------------------------------------+----------+---------+---------------+------------
|
||||||
btree | float_ops | <(double precision,double precision) | 1 | search |
|
btree | array_ops | <(anyarray,anyarray) | 1 | search | | no
|
||||||
btree | float_ops | <=(double precision,double precision) | 2 | search |
|
btree | array_ops | <=(anyarray,anyarray) | 2 | search | | no
|
||||||
btree | float_ops | =(double precision,double precision) | 3 | search |
|
btree | array_ops | =(anyarray,anyarray) | 3 | search | | no
|
||||||
btree | float_ops | >=(double precision,double precision) | 4 | search |
|
btree | array_ops | >=(anyarray,anyarray) | 4 | search | | no
|
||||||
btree | float_ops | >(double precision,double precision) | 5 | search |
|
btree | array_ops | >(anyarray,anyarray) | 5 | search | | no
|
||||||
btree | float_ops | <(real,real) | 1 | search |
|
btree | float_ops | <(double precision,double precision) | 1 | search | | yes
|
||||||
btree | float_ops | <=(real,real) | 2 | search |
|
btree | float_ops | <=(double precision,double precision) | 2 | search | | yes
|
||||||
btree | float_ops | =(real,real) | 3 | search |
|
btree | float_ops | =(double precision,double precision) | 3 | search | | yes
|
||||||
btree | float_ops | >=(real,real) | 4 | search |
|
btree | float_ops | >=(double precision,double precision) | 4 | search | | yes
|
||||||
btree | float_ops | >(real,real) | 5 | search |
|
btree | float_ops | >(double precision,double precision) | 5 | search | | yes
|
||||||
btree | float_ops | <(double precision,real) | 1 | search |
|
btree | float_ops | <(real,real) | 1 | search | | yes
|
||||||
btree | float_ops | <=(double precision,real) | 2 | search |
|
btree | float_ops | <=(real,real) | 2 | search | | yes
|
||||||
btree | float_ops | =(double precision,real) | 3 | search |
|
btree | float_ops | =(real,real) | 3 | search | | yes
|
||||||
btree | float_ops | >=(double precision,real) | 4 | search |
|
btree | float_ops | >=(real,real) | 4 | search | | yes
|
||||||
btree | float_ops | >(double precision,real) | 5 | search |
|
btree | float_ops | >(real,real) | 5 | search | | yes
|
||||||
btree | float_ops | <(real,double precision) | 1 | search |
|
btree | float_ops | <(double precision,real) | 1 | search | | yes
|
||||||
btree | float_ops | <=(real,double precision) | 2 | search |
|
btree | float_ops | <=(double precision,real) | 2 | search | | yes
|
||||||
btree | float_ops | =(real,double precision) | 3 | search |
|
btree | float_ops | =(double precision,real) | 3 | search | | yes
|
||||||
btree | float_ops | >=(real,double precision) | 4 | search |
|
btree | float_ops | >=(double precision,real) | 4 | search | | yes
|
||||||
btree | float_ops | >(real,double precision) | 5 | search |
|
btree | float_ops | >(double precision,real) | 5 | search | | yes
|
||||||
(20 rows)
|
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
|
\dAo * pg_catalog.jsonb_path_ops
|
||||||
List of operators of operator families
|
List of operators of operator families
|
||||||
@ -5388,12 +5393,12 @@ create function psql_df_plpgsql ()
|
|||||||
as $$ begin return; end; $$;
|
as $$ begin return; end; $$;
|
||||||
comment on function psql_df_plpgsql () is 'some comment';
|
comment on function psql_df_plpgsql () is 'some comment';
|
||||||
\df+ psql_df_*
|
\df+ psql_df_*
|
||||||
List of functions
|
List of functions
|
||||||
Schema | Name | Result data type | Argument data types | Type | Volatility | Parallel | Owner | Security | Access privileges | Language | Internal name | Description
|
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 | | internal | dsin |
|
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 | | plpgsql | | some comment
|
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 | | sql | |
|
public | psql_df_sql | integer | x integer | func | volatile | unsafe | regress_psql_user | definer | no | | sql | |
|
||||||
(3 rows)
|
(3 rows)
|
||||||
|
|
||||||
rollback;
|
rollback;
|
||||||
@ -6791,10 +6796,10 @@ REVOKE ALL ON DOMAIN regress_zeropriv_domain FROM CURRENT_USER, PUBLIC;
|
|||||||
CREATE PROCEDURE regress_zeropriv_proc() LANGUAGE sql AS '';
|
CREATE PROCEDURE regress_zeropriv_proc() LANGUAGE sql AS '';
|
||||||
REVOKE ALL ON PROCEDURE regress_zeropriv_proc() FROM CURRENT_USER, PUBLIC;
|
REVOKE ALL ON PROCEDURE regress_zeropriv_proc() FROM CURRENT_USER, PUBLIC;
|
||||||
\df+ regress_zeropriv_proc
|
\df+ regress_zeropriv_proc
|
||||||
List of functions
|
List of functions
|
||||||
Schema | Name | Result data type | Argument data types | Type | Volatility | Parallel | Owner | Security | Access privileges | Language | Internal name | Description
|
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 | (none) | sql | |
|
public | regress_zeropriv_proc | | | proc | volatile | unsafe | regress_zeropriv_owner | invoker | no | (none) | sql | |
|
||||||
(1 row)
|
(1 row)
|
||||||
|
|
||||||
CREATE TABLE regress_zeropriv_tbl (a int);
|
CREATE TABLE regress_zeropriv_tbl (a int);
|
||||||
|
@ -1306,7 +1306,7 @@ drop role regress_partitioning_role;
|
|||||||
\dAc brin pg*.oid*
|
\dAc brin pg*.oid*
|
||||||
\dAf spgist
|
\dAf spgist
|
||||||
\dAf btree int4
|
\dAf btree int4
|
||||||
\dAo+ btree float_ops
|
\dAo+ btree array_ops|float_ops
|
||||||
\dAo * pg_catalog.jsonb_path_ops
|
\dAo * pg_catalog.jsonb_path_ops
|
||||||
\dAp+ btree float_ops
|
\dAp+ btree float_ops
|
||||||
\dAp * pg_catalog.uuid_ops
|
\dAp * pg_catalog.uuid_ops
|
||||||
|
Loading…
x
Reference in New Issue
Block a user