On 2023-10-08 06:14 +0200, Laurenz Albe write:
> On Sat, 2023-10-07 at 20:41 +0200, Erik Wienhold wrote:
> > > If you are happy enough with my patch, shall we mark it as ready for
> > > committer?
> > 
> > I amended your patch to also document the effect of \pset null in this
> > case.  See the attached v2.
> 
> +1
> 
> If you mention in ddl.sgml that you can use "\pset null" to distinguish
> default from no privileges, you should mention that this only works with
> psql.  Many people out there don't use psql.

I don't think this is necessary because that section in ddl.sgml is
already about psql and \dp.

> Also, I'm not sure if "zero privileges" will be readily understood by
> everybody.  Perhaps "no privileges at all, even for the object owner"
> would be a better wording.

Changed in v3 to "empty privileges" with an explanation that this means
"no privileges at all, even for the object owner".

> Perhaps it would also be good to mention this in the psql documentation.

Just once under  \pset null  with a reference to section 5.7?  Something
like "This is also useful for distinguishing default privileges from
empty privileges as explained in Section 5.7."

Or instead under every command affected by this change?  \dp and \ddp
already have such a reference ("The meaning of the privilege display is
explained in Section 5.7.")

I prefer the first one because it's less effort ;)  Also done in v3.

-- 
Erik
>From b7ddd4daa87baab83ad7e857c996b5a4a0b3ffa7 Mon Sep 17 00:00:00 2001
From: Laurenz Albe <laurenz.a...@cybertec.at>
Date: Fri, 6 Oct 2023 22:12:33 +0200
Subject: [PATCH v3] psql: honor "\pset null" in backslash commands

In the output of backslash commands, NULL was always displayed
as empty string, rather than honoring the values set with
"\pset null".

This was surprising, and in some cases it was downright confusing:
for example, default privileges (stored as NULL) were displayed
just like an empty aclitem[], making these cases undistinguishable
in the output.  Add this missing detail to the documentation.

Discussion: 
https://postgr.es/m/96d6885a-5e25-9ae8-4a1a-d7e557a5fe9c%40mtneva.com
---
 doc/src/sgml/ddl.sgml          |  7 ++++--
 doc/src/sgml/ref/psql-ref.sgml |  3 ++-
 src/bin/psql/describe.c        | 43 ----------------------------------
 3 files changed, 7 insertions(+), 46 deletions(-)

diff --git a/doc/src/sgml/ddl.sgml b/doc/src/sgml/ddl.sgml
index 075ff32991..436d655d3c 100644
--- a/doc/src/sgml/ddl.sgml
+++ b/doc/src/sgml/ddl.sgml
@@ -2353,8 +2353,9 @@ GRANT SELECT (col1), UPDATE (col1) ON mytable TO 
miriam_rw;
   <para>
    If the <quote>Access privileges</quote> column is empty for a given
    object, it means the object has default privileges (that is, its
-   privileges entry in the relevant system catalog is null).  Default
-   privileges always include all privileges for the owner, and can include
+   privileges entry in the relevant system catalog is null) or empty privileges
+   (that is, no privileges at all, even for the object owner).
+   Default privileges always include all privileges for the owner, and can 
include
    some privileges for <literal>PUBLIC</literal> depending on the object
    type, as explained above.  The first <command>GRANT</command>
    or <command>REVOKE</command> on an object will instantiate the default
@@ -2362,6 +2363,8 @@ GRANT SELECT (col1), UPDATE (col1) ON mytable TO 
miriam_rw;
    example, <literal>miriam=arwdDxt/miriam</literal>) and then modify them
    per the specified request.  Similarly, entries are shown in <quote>Column
    privileges</quote> only for columns with nondefault privileges.
+   You can, for example, set <literal>\pset null '(default)'</literal> to
+   distinguish default privileges from empty privileges.
    (Note: for this purpose, <quote>default privileges</quote> always means
    the built-in default privileges for the object's type.  An object whose
    privileges have been affected by an <command>ALTER DEFAULT
diff --git a/doc/src/sgml/ref/psql-ref.sgml b/doc/src/sgml/ref/psql-ref.sgml
index d94e3cacfc..966697eb50 100644
--- a/doc/src/sgml/ref/psql-ref.sgml
+++ b/doc/src/sgml/ref/psql-ref.sgml
@@ -3079,7 +3079,8 @@ lo_import 152801
           Sets the string to be printed in place of a null value.
           The default is to print nothing, which can easily be mistaken for
           an empty string. For example, one might prefer <literal>\pset null
-          '(null)'</literal>.
+          '(null)'</literal>. This is also useful for distinguishing default
+          privileges from empty privileges as explained in <xref 
linkend="ddl-priv"/>.
           </para>
           </listitem>
           </varlistentry>
diff --git a/src/bin/psql/describe.c b/src/bin/psql/describe.c
index bac94a338c..224aa22575 100644
--- a/src/bin/psql/describe.c
+++ b/src/bin/psql/describe.c
@@ -124,7 +124,6 @@ describeAggregates(const char *pattern, bool verbose, bool 
showSystem)
        if (!res)
                return false;
 
-       myopt.nullPrint = NULL;
        myopt.title = _("List of aggregate functions");
        myopt.translate_header = true;
 
@@ -197,7 +196,6 @@ describeAccessMethods(const char *pattern, bool verbose)
        if (!res)
                return false;
 
-       myopt.nullPrint = NULL;
        myopt.title = _("List of access methods");
        myopt.translate_header = true;
        myopt.translate_columns = translate_columns;
@@ -262,7 +260,6 @@ describeTablespaces(const char *pattern, bool verbose)
        if (!res)
                return false;
 
-       myopt.nullPrint = NULL;
        myopt.title = _("List of tablespaces");
        myopt.translate_header = true;
 
@@ -585,7 +582,6 @@ describeFunctions(const char *functypes, const char 
*func_pattern,
        if (!res)
                return false;
 
-       myopt.nullPrint = NULL;
        myopt.title = _("List of functions");
        myopt.translate_header = true;
        if (pset.sversion >= 90600)
@@ -702,7 +698,6 @@ describeTypes(const char *pattern, bool verbose, bool 
showSystem)
        if (!res)
                return false;
 
-       myopt.nullPrint = NULL;
        myopt.title = _("List of data types");
        myopt.translate_header = true;
 
@@ -893,7 +888,6 @@ describeOperators(const char *oper_pattern,
        if (!res)
                return false;
 
-       myopt.nullPrint = NULL;
        myopt.title = _("List of operators");
        myopt.translate_header = true;
 
@@ -995,7 +989,6 @@ listAllDbs(const char *pattern, bool verbose)
        if (!res)
                return false;
 
-       myopt.nullPrint = NULL;
        myopt.title = _("List of databases");
        myopt.translate_header = true;
 
@@ -1146,7 +1139,6 @@ permissionsList(const char *pattern, bool showSystem)
        if (!res)
                goto error_return;
 
-       myopt.nullPrint = NULL;
        printfPQExpBuffer(&buf, _("Access privileges"));
        myopt.title = buf.data;
        myopt.translate_header = true;
@@ -1218,7 +1210,6 @@ listDefaultACLs(const char *pattern)
        if (!res)
                goto error_return;
 
-       myopt.nullPrint = NULL;
        printfPQExpBuffer(&buf, _("Default access privileges"));
        myopt.title = buf.data;
        myopt.translate_header = true;
@@ -1417,7 +1408,6 @@ objectDescription(const char *pattern, bool showSystem)
        if (!res)
                return false;
 
-       myopt.nullPrint = NULL;
        myopt.title = _("Object descriptions");
        myopt.translate_header = true;
        myopt.translate_columns = translate_columns;
@@ -3852,7 +3842,6 @@ listDbRoleSettings(const char *pattern, const char 
*pattern2)
        }
        else
        {
-               myopt.nullPrint = NULL;
                myopt.title = _("List of settings");
                myopt.translate_header = true;
 
@@ -3926,7 +3915,6 @@ describeRoleGrants(const char *pattern, bool showSystem)
        if (!res)
                return false;
 
-       myopt.nullPrint = NULL;
        myopt.title = _("List of role grants");
        myopt.translate_header = true;
 
@@ -4122,7 +4110,6 @@ listTables(const char *tabtypes, const char *pattern, 
bool verbose, bool showSys
        }
        else
        {
-               myopt.nullPrint = NULL;
                myopt.title = _("List of relations");
                myopt.translate_header = true;
                myopt.translate_columns = translate_columns;
@@ -4332,7 +4319,6 @@ listPartitionedTables(const char *reltypes, const char 
*pattern, bool verbose)
        initPQExpBuffer(&title);
        appendPQExpBufferStr(&title, tabletitle);
 
-       myopt.nullPrint = NULL;
        myopt.title = title.data;
        myopt.translate_header = true;
        myopt.translate_columns = translate_columns;
@@ -4412,7 +4398,6 @@ listLanguages(const char *pattern, bool verbose, bool 
showSystem)
        if (!res)
                return false;
 
-       myopt.nullPrint = NULL;
        myopt.title = _("List of languages");
        myopt.translate_header = true;
 
@@ -4497,7 +4482,6 @@ listDomains(const char *pattern, bool verbose, bool 
showSystem)
        if (!res)
                return false;
 
-       myopt.nullPrint = NULL;
        myopt.title = _("List of domains");
        myopt.translate_header = true;
 
@@ -4576,7 +4560,6 @@ listConversions(const char *pattern, bool verbose, bool 
showSystem)
        if (!res)
                return false;
 
-       myopt.nullPrint = NULL;
        myopt.title = _("List of conversions");
        myopt.translate_header = true;
        myopt.translate_columns = translate_columns;
@@ -4644,7 +4627,6 @@ describeConfigurationParameters(const char *pattern, bool 
verbose,
        if (!res)
                return false;
 
-       myopt.nullPrint = NULL;
        if (pattern)
                myopt.title = _("List of configuration parameters");
        else
@@ -4726,7 +4708,6 @@ listEventTriggers(const char *pattern, bool verbose)
        if (!res)
                return false;
 
-       myopt.nullPrint = NULL;
        myopt.title = _("List of event triggers");
        myopt.translate_header = true;
        myopt.translate_columns = translate_columns;
@@ -4825,7 +4806,6 @@ listExtendedStats(const char *pattern)
        if (!res)
                return false;
 
-       myopt.nullPrint = NULL;
        myopt.title = _("List of extended statistics");
        myopt.translate_header = true;
 
@@ -4938,7 +4918,6 @@ listCasts(const char *pattern, bool verbose)
        if (!res)
                return false;
 
-       myopt.nullPrint = NULL;
        myopt.title = _("List of casts");
        myopt.translate_header = true;
        myopt.translate_columns = translate_columns;
@@ -5057,7 +5036,6 @@ listCollations(const char *pattern, bool verbose, bool 
showSystem)
        if (!res)
                return false;
 
-       myopt.nullPrint = NULL;
        myopt.title = _("List of collations");
        myopt.translate_header = true;
        myopt.translate_columns = translate_columns;
@@ -5119,7 +5097,6 @@ listSchemas(const char *pattern, bool verbose, bool 
showSystem)
        if (!res)
                goto error_return;
 
-       myopt.nullPrint = NULL;
        myopt.title = _("List of schemas");
        myopt.translate_header = true;
 
@@ -5236,7 +5213,6 @@ listTSParsers(const char *pattern, bool verbose)
        if (!res)
                return false;
 
-       myopt.nullPrint = NULL;
        myopt.title = _("List of text search parsers");
        myopt.translate_header = true;
 
@@ -5384,7 +5360,6 @@ describeOneTSParser(const char *oid, const char *nspname, 
const char *prsname)
        if (!res)
                return false;
 
-       myopt.nullPrint = NULL;
        initPQExpBuffer(&title);
        if (nspname)
                printfPQExpBuffer(&title, _("Text search parser \"%s.%s\""),
@@ -5421,7 +5396,6 @@ describeOneTSParser(const char *oid, const char *nspname, 
const char *prsname)
                return false;
        }
 
-       myopt.nullPrint = NULL;
        if (nspname)
                printfPQExpBuffer(&title, _("Token types for parser \"%s.%s\""),
                                                  nspname, prsname);
@@ -5497,7 +5471,6 @@ listTSDictionaries(const char *pattern, bool verbose)
        if (!res)
                return false;
 
-       myopt.nullPrint = NULL;
        myopt.title = _("List of text search dictionaries");
        myopt.translate_header = true;
 
@@ -5563,7 +5536,6 @@ listTSTemplates(const char *pattern, bool verbose)
        if (!res)
                return false;
 
-       myopt.nullPrint = NULL;
        myopt.title = _("List of text search templates");
        myopt.translate_header = true;
 
@@ -5618,7 +5590,6 @@ listTSConfigs(const char *pattern, bool verbose)
        if (!res)
                return false;
 
-       myopt.nullPrint = NULL;
        myopt.title = _("List of text search configurations");
        myopt.translate_header = true;
 
@@ -5764,7 +5735,6 @@ describeOneTSConfig(const char *oid, const char *nspname, 
const char *cfgname,
                appendPQExpBuffer(&title, _("\nParser: \"%s\""),
                                                  prsname);
 
-       myopt.nullPrint = NULL;
        myopt.title = title.data;
        myopt.footers = NULL;
        myopt.topt.default_footer = false;
@@ -5841,7 +5811,6 @@ listForeignDataWrappers(const char *pattern, bool verbose)
        if (!res)
                return false;
 
-       myopt.nullPrint = NULL;
        myopt.title = _("List of foreign-data wrappers");
        myopt.translate_header = true;
 
@@ -5918,7 +5887,6 @@ listForeignServers(const char *pattern, bool verbose)
        if (!res)
                return false;
 
-       myopt.nullPrint = NULL;
        myopt.title = _("List of foreign servers");
        myopt.translate_header = true;
 
@@ -5974,7 +5942,6 @@ listUserMappings(const char *pattern, bool verbose)
        if (!res)
                return false;
 
-       myopt.nullPrint = NULL;
        myopt.title = _("List of user mappings");
        myopt.translate_header = true;
 
@@ -6047,7 +6014,6 @@ listForeignTables(const char *pattern, bool verbose)
        if (!res)
                return false;
 
-       myopt.nullPrint = NULL;
        myopt.title = _("List of foreign tables");
        myopt.translate_header = true;
 
@@ -6099,7 +6065,6 @@ listExtensions(const char *pattern)
        if (!res)
                return false;
 
-       myopt.nullPrint = NULL;
        myopt.title = _("List of installed extensions");
        myopt.translate_header = true;
 
@@ -6203,7 +6168,6 @@ listOneExtensionContents(const char *extname, const char 
*oid)
        if (!res)
                return false;
 
-       myopt.nullPrint = NULL;
        initPQExpBuffer(&title);
        printfPQExpBuffer(&title, _("Objects in extension \"%s\""), extname);
        myopt.title = title.data;
@@ -6340,7 +6304,6 @@ listPublications(const char *pattern)
        if (!res)
                return false;
 
-       myopt.nullPrint = NULL;
        myopt.title = _("List of publications");
        myopt.translate_header = true;
        myopt.translate_columns = translate_columns;
@@ -6695,7 +6658,6 @@ describeSubscriptions(const char *pattern, bool verbose)
        if (!res)
                return false;
 
-       myopt.nullPrint = NULL;
        myopt.title = _("List of subscriptions");
        myopt.translate_header = true;
        myopt.translate_columns = translate_columns;
@@ -6808,7 +6770,6 @@ listOperatorClasses(const char *access_method_pattern,
        if (!res)
                return false;
 
-       myopt.nullPrint = NULL;
        myopt.title = _("List of operator classes");
        myopt.translate_header = true;
        myopt.translate_columns = translate_columns;
@@ -6897,7 +6858,6 @@ listOperatorFamilies(const char *access_method_pattern,
        if (!res)
                return false;
 
-       myopt.nullPrint = NULL;
        myopt.title = _("List of operator families");
        myopt.translate_header = true;
        myopt.translate_columns = translate_columns;
@@ -6996,7 +6956,6 @@ listOpFamilyOperators(const char *access_method_pattern,
        if (!res)
                return false;
 
-       myopt.nullPrint = NULL;
        myopt.title = _("List of operators of operator families");
        myopt.translate_header = true;
        myopt.translate_columns = translate_columns;
@@ -7089,7 +7048,6 @@ listOpFamilyFunctions(const char *access_method_pattern,
        if (!res)
                return false;
 
-       myopt.nullPrint = NULL;
        myopt.title = _("List of support functions of operator families");
        myopt.translate_header = true;
        myopt.translate_columns = translate_columns;
@@ -7141,7 +7099,6 @@ listLargeObjects(bool verbose)
        if (!res)
                return false;
 
-       myopt.nullPrint = NULL;
        myopt.title = _("Large objects");
        myopt.translate_header = true;
 
-- 
2.42.0

Reply via email to