Dagfinn Ilmari Mannsåker <ilm...@ilmari.org> writes: > Shinya Kato <shinya11.k...@gmail.com> writes: > >> On Fri, Aug 1, 2025 at 2:16 AM Dagfinn Ilmari Mannsåker >> <ilm...@ilmari.org> wrote: >>> >>> Dagfinn Ilmari Mannsåker <ilm...@ilmari.org> writes: >>> >>> > I just noticed that in addition to ALTER ROLE ... RESET being buggy, the >>> > ALTER DATABASE ... RESET query doesn't schema-qualify the unnest() call. >>> > Here's an updated patch series that fixes that too. The first two are >>> > bug fixes to features new in 18 and should IMO be committed before >>> > that's released. The rest can wait for 19. >>> >>> Now that Tomas has committed the two bugfixes, here's the rest of the >>> patches rebased over that.
I also noticed that ALTER SYSTEM RESET tab completes with all variables, not just ones that have been set with ALTER SYSTEM. Getting this right is a bit more complicated, since the only way to distinguish them is pg_settings.sourcefile = '$PGDATA/postgresql.auto.conf', but Windows uses \ for the directory separator, so we'd have to use a regex. But there's no function for escaping a string to use as a literal match in a regex (like Perl's quotemeta()), so we have to use LIKE instead, manually escaping %, _ and \, and accepting any character as the directory separator. If people think this over-complicated, we could just check sourcefile ~ '[\\/]postgresql\.auto\.conf$', and accept false positives if somone has used an include directive with a file with the same name in a different directory. Another complication is that both current_setting('data_directory') and pg_settings.sourcefile are only available to superusers, so I added another version for non-superusers that completes variables they've been granted ALTER SYSTEM on, by querying pg_parameter_acl. - ilmari
>From 623147fe3a52cf4918ee5a45aec56c5fa4f9c9e3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dagfinn=20Ilmari=20Manns=C3=A5ker?= <ilm...@ilmari.org> Date: Mon, 9 Jun 2025 20:39:15 +0100 Subject: [PATCH v5 1/5] Add tab completion for ALTER TABLE ... ALTER COLUMN ... RESET Unlike SET, it only takes parenthesised attribute options. --- src/bin/psql/tab-complete.in.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/bin/psql/tab-complete.in.c b/src/bin/psql/tab-complete.in.c index 1f2ca946fc5..c3c88820dc0 100644 --- a/src/bin/psql/tab-complete.in.c +++ b/src/bin/psql/tab-complete.in.c @@ -2913,9 +2913,13 @@ match_previous_words(int pattern_id, "STATISTICS", "STORAGE", /* a subset of ALTER SEQUENCE options */ "INCREMENT", "MINVALUE", "MAXVALUE", "START", "NO", "CACHE", "CYCLE"); - /* ALTER TABLE ALTER [COLUMN] <foo> SET ( */ - else if (Matches("ALTER", "TABLE", MatchAny, "ALTER", "COLUMN", MatchAny, "SET", "(") || - Matches("ALTER", "TABLE", MatchAny, "ALTER", MatchAny, "SET", "(")) + /* ALTER TABLE ALTER [COLUMN] <foo> RESET */ + else if (Matches("ALTER", "TABLE", MatchAny, "ALTER", "COLUMN", MatchAny, "RESET") || + Matches("ALTER", "TABLE", MatchAny, "ALTER", MatchAny, "RESET")) + COMPLETE_WITH("("); + /* ALTER TABLE ALTER [COLUMN] <foo> SET|RESET ( */ + else if (Matches("ALTER", "TABLE", MatchAny, "ALTER", "COLUMN", MatchAny, "SET|RESET", "(") || + Matches("ALTER", "TABLE", MatchAny, "ALTER", MatchAny, "SET|RESET", "(")) COMPLETE_WITH("n_distinct", "n_distinct_inherited"); /* ALTER TABLE ALTER [COLUMN] <foo> SET COMPRESSION */ else if (Matches("ALTER", "TABLE", MatchAny, "ALTER", "COLUMN", MatchAny, "SET", "COMPRESSION") || -- 2.50.1
>From be2dc71d6f8d6ad30ab96f4eec718a8e1a741c5d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dagfinn=20Ilmari=20Manns=C3=A5ker?= <ilm...@ilmari.org> Date: Mon, 9 Jun 2025 20:41:29 +0100 Subject: [PATCH v5 2/5] Add tab completion for ALTER FOREIGN TABLE ... SET The schema is the only thing that can be set for foreign tables. --- src/bin/psql/tab-complete.in.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/bin/psql/tab-complete.in.c b/src/bin/psql/tab-complete.in.c index c3c88820dc0..ed92e82a4b6 100644 --- a/src/bin/psql/tab-complete.in.c +++ b/src/bin/psql/tab-complete.in.c @@ -2435,6 +2435,10 @@ match_previous_words(int pattern_id, COMPLETE_WITH("ADD", "ALTER", "DISABLE TRIGGER", "DROP", "ENABLE", "INHERIT", "NO INHERIT", "OPTIONS", "OWNER TO", "RENAME", "SET", "VALIDATE CONSTRAINT"); + else if (Matches("ALTER", "FOREIGN", "TABLE", MatchAny, "SET")) + COMPLETE_WITH("SCHEMA"); + else if (Matches("ALTER", "FOREIGN", "TABLE", MatchAny, "SET", "SCHEMA")) + COMPLETE_WITH_QUERY(Query_for_list_of_schemas); /* ALTER INDEX */ else if (Matches("ALTER", "INDEX")) -- 2.50.1
>From 5d9111d03929f8725f015b7a3496c50f1316866e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dagfinn=20Ilmari=20Manns=C3=A5ker?= <ilm...@ilmari.org> Date: Fri, 8 Aug 2025 23:06:36 +0100 Subject: [PATCH v5 3/5] Improve tab completion for RESET Only complete variables that have been set in the current session, plus the keywords ALL, ROLE and SESSION (which will subsequently be completed with AUTHORIZATION). Because we're using Matches() insted of TailMatches(), we can also get rid of the guards against ALTER DATABASE|USER|ROLE ... RESET. --- src/bin/psql/tab-complete.in.c | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/src/bin/psql/tab-complete.in.c b/src/bin/psql/tab-complete.in.c index ed92e82a4b6..dd334d268ca 100644 --- a/src/bin/psql/tab-complete.in.c +++ b/src/bin/psql/tab-complete.in.c @@ -1047,6 +1047,11 @@ static const SchemaQuery Query_for_trigger_of_table = { " WHERE context IN ('user', 'superuser') "\ " AND pg_catalog.lower(name) LIKE pg_catalog.lower('%s')" +#define Query_for_list_of_session_vars \ +"SELECT pg_catalog.lower(name) FROM pg_catalog.pg_settings "\ +" WHERE source = 'session' "\ +" AND pg_catalog.lower(name) LIKE pg_catalog.lower('%s')" + #define Query_for_list_of_show_vars \ "SELECT pg_catalog.lower(name) FROM pg_catalog.pg_settings "\ " WHERE pg_catalog.lower(name) LIKE pg_catalog.lower('%s')" @@ -5027,9 +5032,8 @@ match_previous_words(int pattern_id, /* SET, RESET, SHOW */ /* Complete with a variable name */ - else if (TailMatches("SET|RESET") && - !TailMatches("UPDATE", MatchAny, "SET") && - !TailMatches("ALTER", "DATABASE|USER|ROLE", MatchAny, "RESET")) + else if (TailMatches("SET") && + !TailMatches("UPDATE", MatchAny, "SET")) COMPLETE_WITH_QUERY_VERBATIM_PLUS(Query_for_list_of_set_vars, "CONSTRAINTS", "TRANSACTION", @@ -5037,6 +5041,12 @@ match_previous_words(int pattern_id, "ROLE", "TABLESPACE", "ALL"); + /* Complete with variables set in the current session */ + else if (Matches("RESET")) + COMPLETE_WITH_QUERY_VERBATIM_PLUS(Query_for_list_of_session_vars, + "ALL", + "ROLE", + "SESSION"); else if (Matches("SHOW")) COMPLETE_WITH_QUERY_VERBATIM_PLUS(Query_for_list_of_show_vars, "SESSION AUTHORIZATION", -- 2.50.1
>From efae1fbed9591a519697bacb2730b8b1cdbba736 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dagfinn=20Ilmari=20Manns=C3=A5ker?= <ilm...@ilmari.org> Date: Fri, 8 Aug 2025 23:07:39 +0100 Subject: [PATCH v5 4/5] Improve tab completion for ALTER SYSTEM RESET Only complete variables where sourcefile is `postgresql.conf.auto` in the data directory. --- src/bin/psql/tab-complete.in.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/src/bin/psql/tab-complete.in.c b/src/bin/psql/tab-complete.in.c index dd334d268ca..60bba212f5e 100644 --- a/src/bin/psql/tab-complete.in.c +++ b/src/bin/psql/tab-complete.in.c @@ -1042,6 +1042,13 @@ static const SchemaQuery Query_for_trigger_of_table = { " WHERE context != 'internal' "\ " AND pg_catalog.lower(name) LIKE pg_catalog.lower('%s')" +#define Query_for_list_of_alter_system_reset_vars \ +"SELECT pg_catalog.lower(name) FROM pg_catalog.pg_settings " \ +" WHERE sourcefile LIKE pg_catalog.regexp_replace( " \ +" pg_catalog.current_setting('data_directory'), " \ +" '[_%%\\\\]', '\\\\\\&') || '_postgresql.auto.conf' " \ +" AND pg_catalog.lower(name) LIKE pg_catalog.lower('%s')" + #define Query_for_list_of_set_vars \ "SELECT pg_catalog.lower(name) FROM pg_catalog.pg_settings "\ " WHERE context IN ('user', 'superuser') "\ @@ -2624,8 +2631,10 @@ match_previous_words(int pattern_id, /* ALTER SYSTEM SET, RESET, RESET ALL */ else if (Matches("ALTER", "SYSTEM")) COMPLETE_WITH("SET", "RESET"); - else if (Matches("ALTER", "SYSTEM", "SET|RESET")) - COMPLETE_WITH_QUERY_VERBATIM_PLUS(Query_for_list_of_alter_system_set_vars, + else if (Matches("ALTER", "SYSTEM", "SET")) + COMPLETE_WITH_QUERY_VERBATIM(Query_for_list_of_alter_system_set_vars); + else if (Matches("ALTER", "SYSTEM", "RESET")) + COMPLETE_WITH_QUERY_VERBATIM_PLUS(Query_for_list_of_alter_system_reset_vars, "ALL"); else if (Matches("ALTER", "SYSTEM", "SET", MatchAny)) COMPLETE_WITH("TO"); -- 2.50.1
>From 68883d2ea5a1880b7e8c97024a0f1cfa75d15ad9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dagfinn=20Ilmari=20Manns=C3=A5ker?= <ilm...@ilmari.org> Date: Sat, 9 Aug 2025 00:29:39 +0100 Subject: [PATCH v5 5/5] Improve tab completion for ALTER SYSTEM RESET for non-superusers Non-superusers can only use ALTER SYSTEM on variables they've explicitly been GRANTed access to, and can't read the data_directory setting or pg_settings.sourceline column, so the existing tab completion for ALTER SYSTEM isn't very useful for them. Instead, query pg_parameter_acl to show the variables they do have permission to set via ALTER SYSTEM. --- src/bin/psql/tab-complete.in.c | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/src/bin/psql/tab-complete.in.c b/src/bin/psql/tab-complete.in.c index 60bba212f5e..aee939e98be 100644 --- a/src/bin/psql/tab-complete.in.c +++ b/src/bin/psql/tab-complete.in.c @@ -1049,6 +1049,13 @@ static const SchemaQuery Query_for_trigger_of_table = { " '[_%%\\\\]', '\\\\\\&') || '_postgresql.auto.conf' " \ " AND pg_catalog.lower(name) LIKE pg_catalog.lower('%s')" +#define Query_for_list_of_alter_system_granted_vars \ +"SELECT pg_catalog.lower(parname) FROM pg_catalog.pg_parameter_acl " \ +" WHERE EXISTS (SELECT FROM pg_catalog.aclexplode(paracl) " \ +" WHERE pg_has_role(current_role, grantee, 'usage') " \ +" AND privilege_type = 'ALTER SYSTEM') " \ +" AND pg_catalog.lower(parname) LIKE pg_catalog.lower('%s')" + #define Query_for_list_of_set_vars \ "SELECT pg_catalog.lower(name) FROM pg_catalog.pg_settings "\ " WHERE context IN ('user', 'superuser') "\ @@ -2632,10 +2639,16 @@ match_previous_words(int pattern_id, else if (Matches("ALTER", "SYSTEM")) COMPLETE_WITH("SET", "RESET"); else if (Matches("ALTER", "SYSTEM", "SET")) - COMPLETE_WITH_QUERY_VERBATIM(Query_for_list_of_alter_system_set_vars); + if (is_superuser()) + COMPLETE_WITH_QUERY_VERBATIM(Query_for_list_of_alter_system_set_vars); + else + COMPLETE_WITH_QUERY_VERBATIM(Query_for_list_of_alter_system_granted_vars); else if (Matches("ALTER", "SYSTEM", "RESET")) - COMPLETE_WITH_QUERY_VERBATIM_PLUS(Query_for_list_of_alter_system_reset_vars, - "ALL"); + if (is_superuser()) + COMPLETE_WITH_QUERY_VERBATIM_PLUS(Query_for_list_of_alter_system_reset_vars, + "ALL"); + else + COMPLETE_WITH_QUERY_VERBATIM(Query_for_list_of_alter_system_granted_vars); else if (Matches("ALTER", "SYSTEM", "SET", MatchAny)) COMPLETE_WITH("TO"); /* ALTER VIEW <name> */ -- 2.50.1