Thread: Tab completion for large objects

Tab completion for large objects

From
Dagfinn Ilmari Mannsåker
Date:
Hi hackers,

I noticed that psql's tab completion suggested TO immediately after
GRANT ... ON LARGE OBJECT, and not after ON LARGE OBJECT <oid>.  This is
because LARGE OBJECT is the only two-word object type, so it thinks
LARGE is the object type and OBJECT is the name.  Attached are three
patches that address this and other LO-related tab completion issues:

 1. Tab complete OBJECT after GRANT|REVOKE ... ON LARGE, and TO/FROM
    after GRANT|REVOKE ... ON LARGE OBJECT

 2. Tab complete filenames after \lo_export <oid>

 3. Tab complete large object OIDs where relevant.  This is less useful
    than completing names like for other objects, but it might still
    be handy.  Separate patch in case it proves controversial or is
    deemed useless.

- ilmari

From b657b3d1a31af927231a7d51002d00d830f473b7 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Dagfinn=20Ilmari=20Manns=C3=A5ker?= <ilmari@ilmari.org>
Date: Tue, 8 Jul 2025 19:21:59 +0100
Subject: [PATCH 1/3] Improve tab completion around GRANT/REVOKE ... ON LARGE
 OBJECT

Because large objects are the only two-word object type, it was
completing with TO or FROM immediately after LARGE OBJECT, not after
having entered the OID.
---
 src/bin/psql/tab-complete.in.c | 8 ++++++--
 1 file changed, 6 insertions(+), 2 deletions(-)

diff --git a/src/bin/psql/tab-complete.in.c b/src/bin/psql/tab-complete.in.c
index 53e7d35fe98..fe97179b979 100644
--- a/src/bin/psql/tab-complete.in.c
+++ b/src/bin/psql/tab-complete.in.c
@@ -4531,6 +4531,8 @@ match_previous_words(int pattern_id,
             COMPLETE_WITH_VERSIONED_SCHEMA_QUERY(Query_for_list_of_functions);
         else if (TailMatches("LANGUAGE"))
             COMPLETE_WITH_QUERY(Query_for_list_of_languages);
+        else if (TailMatches("LARGE"))
+            COMPLETE_WITH("OBJECT");
         else if (TailMatches("PROCEDURE"))
             COMPLETE_WITH_VERSIONED_SCHEMA_QUERY(Query_for_list_of_procedures);
         else if (TailMatches("ROUTINE"))
@@ -4589,9 +4591,11 @@ match_previous_words(int pattern_id,
     else if (Matches("ALTER", "DEFAULT", "PRIVILEGES", MatchAnyN, "TO", MatchAny))
         COMPLETE_WITH("WITH GRANT OPTION");
     /* Complete "GRANT/REVOKE ... ON * *" with TO/FROM */
-    else if (Matches("GRANT", MatchAnyN, "ON", MatchAny, MatchAny))
+    else if (Matches("GRANT", MatchAnyN, "ON", MatchAny, MatchAny) ||
+             Matches("GRANT", MatchAnyN, "ON", "LARGE", "OBJECT", MatchAny))
         COMPLETE_WITH("TO");
-    else if (Matches("REVOKE", MatchAnyN, "ON", MatchAny, MatchAny))
+    else if (Matches("REVOKE", MatchAnyN, "ON", MatchAny, MatchAny) ||
+             Matches("REVOKE", MatchAnyN, "ON", "LARGE", "OBJECT", MatchAny))
         COMPLETE_WITH("FROM");
 
     /* Complete "GRANT/REVOKE * ON ALL * IN SCHEMA *" with TO/FROM */
-- 
2.50.0

From 20715236941ecb7884545fa70fadbd49a026dd3c Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Dagfinn=20Ilmari=20Manns=C3=A5ker?= <ilmari@ilmari.org>
Date: Tue, 8 Jul 2025 19:22:13 +0100
Subject: [PATCH 2/3] Tab complete filenames after \lo_export <oid>

---
 src/bin/psql/tab-complete.in.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/src/bin/psql/tab-complete.in.c b/src/bin/psql/tab-complete.in.c
index fe97179b979..922895d0d0f 100644
--- a/src/bin/psql/tab-complete.in.c
+++ b/src/bin/psql/tab-complete.in.c
@@ -5468,7 +5468,8 @@ match_previous_words(int pattern_id,
         COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_views);
     else if (TailMatchesCS("\\cd|\\e|\\edit|\\g|\\gx|\\i|\\include|"
                            "\\ir|\\include_relative|\\o|\\out|"
-                           "\\s|\\w|\\write|\\lo_import"))
+                           "\\s|\\w|\\write|\\lo_import") ||
+             TailMatchesCS("\\lo_export", MatchAny))
     {
         completion_charp = "\\";
         completion_force_quote = false;
-- 
2.50.0

From a16c467898f5579f4961bdfe6db5dd3c52e5820a Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Dagfinn=20Ilmari=20Manns=C3=A5ker?= <ilmari@ilmari.org>
Date: Tue, 8 Jul 2025 19:23:00 +0100
Subject: [PATCH 3/3] Add tab completion for large object OIDs

For GRANT, REVOKE, \lo_unlink and \lo_export.

This is less useful than names, but might still be handy.
---
 src/bin/psql/tab-complete.in.c | 10 ++++++++++
 1 file changed, 10 insertions(+)

diff --git a/src/bin/psql/tab-complete.in.c b/src/bin/psql/tab-complete.in.c
index 922895d0d0f..227747d9897 100644
--- a/src/bin/psql/tab-complete.in.c
+++ b/src/bin/psql/tab-complete.in.c
@@ -978,6 +978,11 @@ static const SchemaQuery Query_for_trigger_of_table = {
     .refnamespace = "c1.relnamespace",
 };
 
+static SchemaQuery Query_for_list_of_large_objects = {
+    .catname = "pg_catalog.pg_largeobject_metadata lom",
+    .result = "lom.oid::pg_catalog.text",
+};
+
 
 /*
  * Queries to get lists of names of various kinds of things, possibly
@@ -4552,6 +4557,9 @@ match_previous_words(int pattern_id,
         else
             COMPLETE_WITH("FROM");
     }
+    else if (TailMatches("GRANT|REVOKE", MatchAny, "ON", "LARGE", "OBJECT") ||
+             TailMatches("REVOKE", "GRANT", "OPTION", "FOR", MatchAny, "ON", "LARGE", "OBJECT"))
+        COMPLETE_WITH_SCHEMA_QUERY_VERBATIM(Query_for_list_of_large_objects);
 
     /*
      * Complete "GRANT/REVOKE ... TO/FROM" with username, PUBLIC,
@@ -5406,6 +5414,8 @@ match_previous_words(int pattern_id,
     }
     else if (TailMatchesCS("\\l*") && !TailMatchesCS("\\lo*"))
         COMPLETE_WITH_QUERY(Query_for_list_of_databases);
+    else if (TailMatchesCS("\\lo_unlink|\\lo_export"))
+        COMPLETE_WITH_SCHEMA_QUERY_VERBATIM(Query_for_list_of_large_objects);
     else if (TailMatchesCS("\\password"))
         COMPLETE_WITH_QUERY(Query_for_list_of_roles);
     else if (TailMatchesCS("\\pset"))
-- 
2.50.0


Re: Tab completion for large objects

From
Fujii Masao
Date:

On 2025/07/09 3:50, Dagfinn Ilmari Mannsåker wrote:
> Hi hackers,
> 
> I noticed that psql's tab completion suggested TO immediately after
> GRANT ... ON LARGE OBJECT, and not after ON LARGE OBJECT <oid>.  This is
> because LARGE OBJECT is the only two-word object type, so it thinks
> LARGE is the object type and OBJECT is the name.  Attached are three
> patches that address this and other LO-related tab completion issues:
> 
>   1. Tab complete OBJECT after GRANT|REVOKE ... ON LARGE, and TO/FROM
>      after GRANT|REVOKE ... ON LARGE OBJECT

Thanks for the patches!

Regarding the 0001 patch, Nagata-san already proposed a similar patch in [1].
His version handles not only "LARGE OBJECT" but also another two-word object type,
"FOREIGN SERVER".

Regards,

[1] https://postgr.es/m/20250611135737.bb7d3135141248819704ebca@sraoss.co.jp

-- 
Fujii Masao
NTT DATA Japan Corporation