v3-0001-Print-empty-table-when-a-given-object-is-not-foun.patch
application/octet-stream
Filename: v3-0001-Print-empty-table-when-a-given-object-is-not-foun.patch
Type: application/octet-stream
Part: 0
Patch
Same data as JSON:
GET /api/v1/attachments/:id/patch
the parsed metadata as JSON — format, series position, per-file stats; never the diff bytes.
API reference →
Format: format-patch
Series: patch v3-0001
Subject: Print empty table when a given object is not found in a slash command
| File | + | − |
|---|---|---|
| src/bin/psql/describe.c | 232 | 145 |
| src/bin/psql/t/001_basic.pl | 26 | 0 |
From 86ea629bc4ede9c51f9c000caddf1969b593b569 Mon Sep 17 00:00:00 2001
From: Abhishek Chanda <abhishek.becs@gmail.com>
Date: Sat, 12 Apr 2025 22:30:17 -0500
Subject: [PATCH v3] Print empty table when a given object is not found in a
slash command
Currently, in a few cases we return an error of the form
Did not find any XXXX named YYYY while in some cases we
print a table with no rows. This patch changes a few of
the former to the later so that we have an uniform
interface.
---
src/bin/psql/describe.c | 377 ++++++++++++++++++++++--------------
src/bin/psql/t/001_basic.pl | 26 +++
2 files changed, 258 insertions(+), 145 deletions(-)
diff --git a/src/bin/psql/describe.c b/src/bin/psql/describe.c
index 36f24502842..de1bb31b231 100644
--- a/src/bin/psql/describe.c
+++ b/src/bin/psql/describe.c
@@ -136,6 +136,12 @@ describeAggregates(const char *pattern, bool verbose, bool showSystem)
printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
+ if (pattern && PQntuples(res) == 0)
+ {
+ PQclear(res);
+ return false;
+ }
+
PQclear(res);
return true;
}
@@ -210,6 +216,12 @@ describeAccessMethods(const char *pattern, bool verbose)
printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
+ if (pattern && PQntuples(res) == 0)
+ {
+ PQclear(res);
+ return false;
+ }
+
PQclear(res);
return true;
}
@@ -272,6 +284,12 @@ describeTablespaces(const char *pattern, bool verbose)
printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
+ if (pattern && PQntuples(res) == 0)
+ {
+ PQclear(res);
+ return false;
+ }
+
PQclear(res);
return true;
}
@@ -621,6 +639,12 @@ describeFunctions(const char *functypes, const char *func_pattern,
printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
+ if (func_pattern && PQntuples(res) == 0)
+ {
+ PQclear(res);
+ return false;
+ }
+
PQclear(res);
return true;
@@ -727,6 +751,12 @@ describeTypes(const char *pattern, bool verbose, bool showSystem)
printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
+ if (pattern && PQntuples(res) == 0)
+ {
+ PQclear(res);
+ return false;
+ }
+
PQclear(res);
return true;
}
@@ -928,6 +958,12 @@ describeOperators(const char *oper_pattern,
printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
+ if (oper_pattern && PQntuples(res) == 0)
+ {
+ PQclear(res);
+ return false;
+ }
+
PQclear(res);
return true;
@@ -1037,6 +1073,12 @@ listAllDbs(const char *pattern, bool verbose)
printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
+ if (pattern && PQntuples(res) == 0)
+ {
+ PQclear(res);
+ return false;
+ }
+
PQclear(res);
return true;
}
@@ -1270,6 +1312,13 @@ listDefaultACLs(const char *pattern)
printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
+ if (pattern && PQntuples(res) == 0)
+ {
+ termPQExpBuffer(&buf);
+ PQclear(res);
+ return false;
+ }
+
termPQExpBuffer(&buf);
PQclear(res);
return true;
@@ -1522,16 +1571,14 @@ describeTableDetails(const char *pattern, bool verbose, bool showSystem)
if (PQntuples(res) == 0)
{
- if (!pset.quiet)
- {
- if (pattern)
- pg_log_error("Did not find any relation named \"%s\".",
- pattern);
- else
- pg_log_error("Did not find any relations.");
- }
PQclear(res);
- return false;
+ /*
+ * Print an empty table and return failure when no objects match
+ */
+ if (pattern)
+ return listTables("tvmsE", pattern, verbose, showSystem);
+ else
+ return true;
}
for (i = 0; i < PQntuples(res); i++)
@@ -1720,14 +1767,6 @@ describeOneTableDetails(const char *schemaname,
if (!res)
goto error_return;
- /* Did we get anything? */
- if (PQntuples(res) == 0)
- {
- if (!pset.quiet)
- pg_log_error("Did not find any relation with OID %s.", oid);
- goto error_return;
- }
-
tableinfo.checks = atoi(PQgetvalue(res, 0, 0));
tableinfo.relkind = *(PQgetvalue(res, 0, 1));
tableinfo.hasindex = strcmp(PQgetvalue(res, 0, 2), "t") == 0;
@@ -3797,6 +3836,7 @@ describeRoles(const char *pattern, bool verbose, bool showSystem)
return false;
nrows = PQntuples(res);
+
attr = pg_malloc0((nrows + 1) * sizeof(*attr));
printTableInit(&cont, &myopt, _("List of roles"), ncols, nrows);
@@ -3873,6 +3913,12 @@ describeRoles(const char *pattern, bool verbose, bool showSystem)
free(attr[i]);
free(attr);
+ if (pattern && nrows == 0)
+ {
+ PQclear(res);
+ return false;
+ }
+
PQclear(res);
return true;
}
@@ -3921,29 +3967,15 @@ listDbRoleSettings(const char *pattern, const char *pattern2)
if (!res)
return false;
- /*
- * Most functions in this file are content to print an empty table when
- * there are no matching objects. We intentionally deviate from that
- * here, but only in !quiet mode, because of the possibility that the user
- * is confused about what the two pattern arguments mean.
- */
- if (PQntuples(res) == 0 && !pset.quiet)
- {
- if (pattern && pattern2)
- pg_log_error("Did not find any settings for role \"%s\" and database \"%s\".",
- pattern, pattern2);
- else if (pattern)
- pg_log_error("Did not find any settings for role \"%s\".",
- pattern);
- else
- pg_log_error("Did not find any settings.");
- }
- else
- {
- myopt.title = _("List of settings");
- myopt.translate_header = true;
+ myopt.title = _("List of settings");
+ myopt.translate_header = true;
- printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
+ printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
+
+ if ((pattern || pattern2) && PQntuples(res) == 0)
+ {
+ PQclear(res);
+ return false;
}
PQclear(res);
@@ -4018,6 +4050,12 @@ describeRoleGrants(const char *pattern, bool showSystem)
printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
+ if (pattern && PQntuples(res) == 0)
+ {
+ PQclear(res);
+ return false;
+ }
+
PQclear(res);
return true;
}
@@ -4201,76 +4239,25 @@ listTables(const char *tabtypes, const char *pattern, bool verbose, bool showSys
if (!res)
return false;
- /*
- * Most functions in this file are content to print an empty table when
- * there are no matching objects. We intentionally deviate from that
- * here, but only in !quiet mode, for historical reasons.
- */
- if (PQntuples(res) == 0 && !pset.quiet)
- {
- if (pattern)
- {
- if (ntypes != 1)
- pg_log_error("Did not find any relations named \"%s\".",
- pattern);
- else if (showTables)
- pg_log_error("Did not find any tables named \"%s\".",
- pattern);
- else if (showIndexes)
- pg_log_error("Did not find any indexes named \"%s\".",
- pattern);
- else if (showViews)
- pg_log_error("Did not find any views named \"%s\".",
- pattern);
- else if (showMatViews)
- pg_log_error("Did not find any materialized views named \"%s\".",
- pattern);
- else if (showSeq)
- pg_log_error("Did not find any sequences named \"%s\".",
- pattern);
- else if (showForeign)
- pg_log_error("Did not find any foreign tables named \"%s\".",
- pattern);
- else /* should not get here */
- pg_log_error_internal("Did not find any ??? named \"%s\".",
- pattern);
- }
- else
- {
- if (ntypes != 1)
- pg_log_error("Did not find any relations.");
- else if (showTables)
- pg_log_error("Did not find any tables.");
- else if (showIndexes)
- pg_log_error("Did not find any indexes.");
- else if (showViews)
- pg_log_error("Did not find any views.");
- else if (showMatViews)
- pg_log_error("Did not find any materialized views.");
- else if (showSeq)
- pg_log_error("Did not find any sequences.");
- else if (showForeign)
- pg_log_error("Did not find any foreign tables.");
- else /* should not get here */
- pg_log_error_internal("Did not find any ??? relations.");
- }
- }
- else
- {
- myopt.title =
- (ntypes != 1) ? _("List of relations") :
- (showTables) ? _("List of tables") :
- (showIndexes) ? _("List of indexes") :
- (showViews) ? _("List of views") :
- (showMatViews) ? _("List of materialized views") :
- (showSeq) ? _("List of sequences") :
- (showForeign) ? _("List of foreign tables") :
- "List of ???"; /* should not get here */
- myopt.translate_header = true;
- myopt.translate_columns = translate_columns;
- myopt.n_translate_columns = lengthof(translate_columns);
+ myopt.title =
+ (ntypes != 1) ? _("List of relations") :
+ (showTables) ? _("List of tables") :
+ (showIndexes) ? _("List of indexes") :
+ (showViews) ? _("List of views") :
+ (showMatViews) ? _("List of materialized views") :
+ (showSeq) ? _("List of sequences") :
+ (showForeign) ? _("List of foreign tables") :
+ "List of ???"; /* should not get here */
+ 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);
+
+ if (pattern && PQntuples(res) == 0)
+ {
+ PQclear(res);
+ return false;
}
PQclear(res);
@@ -4568,6 +4555,12 @@ listLanguages(const char *pattern, bool verbose, bool showSystem)
printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
+ if (pattern && PQntuples(res) == 0)
+ {
+ PQclear(res);
+ return false;
+ }
+
PQclear(res);
return true;
}
@@ -4652,6 +4645,12 @@ listDomains(const char *pattern, bool verbose, bool showSystem)
printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
+ if (pattern && PQntuples(res) == 0)
+ {
+ PQclear(res);
+ return false;
+ }
+
PQclear(res);
return true;
}
@@ -4732,6 +4731,12 @@ listConversions(const char *pattern, bool verbose, bool showSystem)
printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
+ if (pattern && PQntuples(res) == 0)
+ {
+ PQclear(res);
+ return false;
+ }
+
PQclear(res);
return true;
}
@@ -4800,6 +4805,12 @@ describeConfigurationParameters(const char *pattern, bool verbose,
printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
+ if (pattern && PQntuples(res) == 0)
+ {
+ PQclear(res);
+ return false;
+ }
+
PQclear(res);
return true;
}
@@ -4880,6 +4891,12 @@ listEventTriggers(const char *pattern, bool verbose)
printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
+ if (pattern && PQntuples(res) == 0)
+ {
+ PQclear(res);
+ return false;
+ }
+
PQclear(res);
return true;
}
@@ -4976,6 +4993,12 @@ listExtendedStats(const char *pattern)
printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
+ if (pattern && PQntuples(res) == 0)
+ {
+ PQclear(res);
+ return false;
+ }
+
PQclear(res);
return true;
}
@@ -5223,6 +5246,12 @@ listCollations(const char *pattern, bool verbose, bool showSystem)
printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
+ if (pattern && PQntuples(res) == 0)
+ {
+ PQclear(res);
+ return false;
+ }
+
PQclear(res);
return true;
}
@@ -5327,6 +5356,13 @@ listSchemas(const char *pattern, bool verbose, bool showSystem)
printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
+ if (pattern && PQntuples(res) == 0)
+ {
+ termPQExpBuffer(&buf);
+ PQclear(res);
+ return false;
+ }
+
termPQExpBuffer(&buf);
PQclear(res);
@@ -5398,6 +5434,12 @@ listTSParsers(const char *pattern, bool verbose)
printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
+ if (pattern && PQntuples(res) == 0)
+ {
+ PQclear(res);
+ return false;
+ }
+
PQclear(res);
return true;
}
@@ -5440,16 +5482,11 @@ listTSParsersVerbose(const char *pattern)
if (PQntuples(res) == 0)
{
- if (!pset.quiet)
- {
- if (pattern)
- pg_log_error("Did not find any text search parser named \"%s\".",
- pattern);
- else
- pg_log_error("Did not find any text search parsers.");
- }
PQclear(res);
- return false;
+ if (pattern)
+ return listTSParsers(pattern, false);
+ else
+ return true;
}
for (i = 0; i < PQntuples(res); i++)
@@ -5775,6 +5812,12 @@ listTSConfigs(const char *pattern, bool verbose)
printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
+ if (pattern && PQntuples(res) == 0)
+ {
+ PQclear(res);
+ return false;
+ }
+
PQclear(res);
return true;
}
@@ -5818,16 +5861,11 @@ listTSConfigsVerbose(const char *pattern)
if (PQntuples(res) == 0)
{
- if (!pset.quiet)
- {
- if (pattern)
- pg_log_error("Did not find any text search configuration named \"%s\".",
- pattern);
- else
- pg_log_error("Did not find any text search configurations.");
- }
PQclear(res);
- return false;
+ if (pattern)
+ return listTSConfigs(pattern, false);
+ else
+ return true;
}
for (i = 0; i < PQntuples(res); i++)
@@ -5996,6 +6034,12 @@ listForeignDataWrappers(const char *pattern, bool verbose)
printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
+ if (pattern && PQntuples(res) == 0)
+ {
+ PQclear(res);
+ return false;
+ }
+
PQclear(res);
return true;
}
@@ -6072,6 +6116,12 @@ listForeignServers(const char *pattern, bool verbose)
printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
+ if (pattern && PQntuples(res) == 0)
+ {
+ PQclear(res);
+ return false;
+ }
+
PQclear(res);
return true;
}
@@ -6127,6 +6177,12 @@ listUserMappings(const char *pattern, bool verbose)
printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
+ if (pattern && PQntuples(res) == 0)
+ {
+ PQclear(res);
+ return false;
+ }
+
PQclear(res);
return true;
}
@@ -6199,6 +6255,12 @@ listForeignTables(const char *pattern, bool verbose)
printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
+ if (pattern && PQntuples(res) == 0)
+ {
+ PQclear(res);
+ return false;
+ }
+
PQclear(res);
return true;
}
@@ -6253,6 +6315,12 @@ listExtensions(const char *pattern)
printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
+ if (pattern && PQntuples(res) == 0)
+ {
+ PQclear(res);
+ return false;
+ }
+
PQclear(res);
return true;
}
@@ -6293,16 +6361,11 @@ listExtensionContents(const char *pattern)
if (PQntuples(res) == 0)
{
- if (!pset.quiet)
- {
- if (pattern)
- pg_log_error("Did not find any extension named \"%s\".",
- pattern);
- else
- pg_log_error("Did not find any extensions.");
- }
PQclear(res);
- return false;
+ if (pattern)
+ return listExtensions(pattern);
+ else
+ return true;
}
for (i = 0; i < PQntuples(res); i++)
@@ -6510,6 +6573,12 @@ listPublications(const char *pattern)
printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
+ if (pattern && PQntuples(res) == 0)
+ {
+ PQclear(res);
+ return false;
+ }
+
PQclear(res);
return true;
@@ -6660,18 +6729,12 @@ describePublications(const char *pattern)
if (PQntuples(res) == 0)
{
- if (!pset.quiet)
- {
- if (pattern)
- pg_log_error("Did not find any publication named \"%s\".",
- pattern);
- else
- pg_log_error("Did not find any publications.");
- }
-
termPQExpBuffer(&buf);
PQclear(res);
- return false;
+ if (pattern)
+ return listPublications(pattern);
+ else
+ return true;
}
for (i = 0; i < PQntuples(res); i++)
@@ -7051,6 +7114,12 @@ listOperatorClasses(const char *access_method_pattern,
printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
+ if ((access_method_pattern || type_pattern) && PQntuples(res) == 0)
+ {
+ PQclear(res);
+ return false;
+ }
+
PQclear(res);
return true;
@@ -7139,6 +7208,12 @@ listOperatorFamilies(const char *access_method_pattern,
printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
+ if ((access_method_pattern || type_pattern) && PQntuples(res) == 0)
+ {
+ PQclear(res);
+ return false;
+ }
+
PQclear(res);
return true;
@@ -7246,6 +7321,12 @@ listOpFamilyOperators(const char *access_method_pattern,
printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
+ if ((access_method_pattern || family_pattern) && PQntuples(res) == 0)
+ {
+ PQclear(res);
+ return false;
+ }
+
PQclear(res);
return true;
@@ -7338,6 +7419,12 @@ listOpFamilyFunctions(const char *access_method_pattern,
printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
+ if ((access_method_pattern || family_pattern) && PQntuples(res) == 0)
+ {
+ PQclear(res);
+ return false;
+ }
+
PQclear(res);
return true;
diff --git a/src/bin/psql/t/001_basic.pl b/src/bin/psql/t/001_basic.pl
index cf07a9dbd5e..011a6508df0 100644
--- a/src/bin/psql/t/001_basic.pl
+++ b/src/bin/psql/t/001_basic.pl
@@ -537,4 +537,30 @@ psql_fails_like(
qr/backslash commands are restricted; only \\unrestrict is allowed/,
'meta-command in restrict mode fails');
+# Test that \d commands return exit code 1 when pattern matches nothing
+# and don't print "Did not find" error messages
+{
+ my ($ret, $stdout, $stderr);
+
+ ($ret, $stdout, $stderr) = $node->psql('postgres', '\\d nonexistent_table');
+ isnt($ret, 0, '\\d with non-existent pattern: exit code not 0');
+ unlike($stderr, qr/Did not find/, '\\d with non-existent pattern: no error message');
+
+ ($ret, $stdout, $stderr) = $node->psql('postgres', '\\dt nonexistent_table');
+ isnt($ret, 0, '\\dt with non-existent pattern: exit code not 0');
+ unlike($stderr, qr/Did not find/, '\\dt with non-existent pattern: no error message');
+
+ ($ret, $stdout, $stderr) = $node->psql('postgres', '\\df nonexistent_func');
+ isnt($ret, 0, '\\df with non-existent pattern: exit code not 0');
+ unlike($stderr, qr/Did not find/, '\\df with non-existent pattern: no error message');
+
+ ($ret, $stdout, $stderr) = $node->psql('postgres', '\\dx+ nonexistent_ext');
+ isnt($ret, 0, '\\dx+ with non-existent pattern: exit code not 0');
+ unlike($stderr, qr/Did not find/, '\\dx+ with non-existent pattern: no error message');
+
+ # Test that \d commands without patterns succeed even with no results
+ ($ret, $stdout, $stderr) = $node->psql('postgres', '\\d');
+ is($ret, 0, '\\d without pattern: exit code 0');
+}
+
done_testing();
--
2.50.1