Обсуждение: [PATCH] psql: tab completion for ALTER ROLE ... IN DATABASE ...
I found myself needing to work with ALTER ROLE ... IN DATABASE ... recently
and was annoyed by the lack of tab completion for this, so patch attached.
Regards
Ian Barwick
Вложения
Hi
I found myself needing to work with ALTER ROLE ... IN DATABASE ... recently
and was annoyed by the lack of tab completion for this, so patch attached.
Regards
Ian Barwick
Re: [PATCH] psql: tab completion for ALTER ROLE ... IN DATABASE ...
Ian Lawrence Barwick <barwick@gmail.com> writes:
> Hi
>
> I found myself needing to work with ALTER ROLE ... IN DATABASE ... recently
> and was annoyed by the lack of tab completion for this, so patch attached.
A noble goal, but unfortunately th RESET form can't work properly due to
limitations of the tab completion system.
> + /* ALTER USER,ROLE <name> IN DATABASE */
> + else if (HeadMatches("ALTER", "USER|ROLE", MatchAny, "IN"))
> + {
[...]
> + else if (TailMatches("DATABASE", MatchAny, "RESET"))
> + {
> + set_completion_reference(prev5_wd);
> + COMPLETE_WITH_QUERY_PLUS(Query_for_list_of_user_vars, "ALL");
This queries pg_roles.rolconfig, which only contains variables set for
the user in all databases, not in the specified database. Instead,
you'd need to query pg_db_role_setting WHERE setdatabase = (SELECT oid
FROM pg_database WHERE datname = '%s') AND setrole = '%s'::regrole, but
unfortunately the tab completion system doesn't let you more than one
previous word in the query. I guess you could query WHERE setdatabase
<> 0, to get variables set for the user across all databases, not just
the specified one.
Also, alter ALTER ROLE ALL RESET needs separate handling, filtering
where setrole = 0, which is actually possible in the current system.
- ilmari
Hi Ian,
+1 for the patch,LGTM
But after applying the patch i can be able to apply all the results
except the reset options user variables
postgres=#
postgres=# alter role bob
BYPASSRLS CREATEROLE INHERIT NOCREATEDB
NOLOGIN PASSWORD RESET
VALID UNTIL
CONNECTION LIMIT ENCRYPTED PASSWORD LOGIN
NOCREATEROLE NOREPLICATION RENAME TO SET
WITH
CREATEDB IN DATABASE NOBYPASSRLS NOINHERIT
NOSUPERUSER REPLICATION SUPERUSER
postgres=# alter role bob in DATABASE
postgres template0 template1
postgres=# alter role bob in DATABASE postgres
RESET SET
postgres=# alter role bob in DATABASE postgres reset ALL
postgres=# alter role bob in DATABASE postgres reset ALL
also i cross verified that my system doesn't have variables so it
returns 0 rows?but:
postgres=# SELECT name FROM pg_settings LIMIT 5;
name
----------------------------
allow_alter_system
allow_in_place_tablespaces
allow_system_table_mods
application_name
archive_cleanup_command
(5 rows)
Can you check this ?
-regards
Vasuki M
On Fri, Nov 21, 2025 at 8:44 AM Ian Lawrence Barwick <barwick@gmail.com> wrote:
>
> Hi
>
> I found myself needing to work with ALTER ROLE ... IN DATABASE ... recently
> and was annoyed by the lack of tab completion for this, so patch attached.
>
>
> Regards
>
> Ian Barwick
>
Hi Ian,
+1 for the patch,LGTM
But after applying the patch i can be able to apply all the results
except the reset options user variables
postgres=# alter role bob in DATABASE postgres reset ALL
also i cross verified that my system doesn't have variables so it
returns 0 rows?but:
postgres=# SELECT name FROM pg_settings LIMIT 5;
name
----------------------------
allow_alter_system
allow_in_place_tablespaces
allow_system_table_mods
application_name
archive_cleanup_command
(5 rows)
+ else if (TailMatches("DATABASE", MatchAny, "RESET"))
+ {
+ set_completion_reference(prev5_wd);
+ COMPLETE_WITH_QUERY_PLUS(Query_for_list_of_user_vars, "ALL");
+ }
#define Query_for_list_of_user_vars \
"SELECT conf FROM ("\
" SELECT rolname, pg_catalog.split_part(pg_catalog.unnest(rolconfig),'=',1) conf"\
" FROM pg_catalog.pg_roles"\
" ) s"\
" WHERE s.conf like '%s' "\
" AND s.rolname LIKE '%s'"
Hello all,
Based on the discussion, I have updated the patch to handle the RESET form correctly without modifying psql’s tab-completion APIs.
Both the current database connection and the parsed input tokens are already available via pset.db and the word tokens.The new patch extracts:
the role name from the parsed tokens (prev5_wd), and
the database name from the parsed tokens (prev2_wd),
and uses these to query pg_db_role_setting for variables that are actually set for the specific (role, database) pair.
Literal quoting is now done with PQescapeLiteral(pset.db, …), per libpq conventions, so no new helper functions were needed.
SET
After
ALTER ROLE <role> IN DATABASE <dbname> SET <TAB>
psql completes from Query_for_list_of_set_vars (same behavior as plain ALTER ROLE … SET).
RESET
After
ALTER ROLE <role> IN DATABASE <dbname> RESET <TAB>
psql now completes with the GUC names recorded in pg_db_role_setting for that specific (role,database), plus ALL.
When no settings exist, only ALL is suggested.
This mirrors the existing behavior of ALTER DATABASE … RESET.
I have attached the patch.
Regards,
Vasuki
Hi
I found myself needing to work with ALTER ROLE ... IN DATABASE ... recently
and was annoyed by the lack of tab completion for this, so patch attached.
Regards
Ian Barwick
Вложения
As i saw the proposed patch by Ian failed with CI https://commitfest.postgresql.org/patch/6244/
Guide me with the patch
Regards,
Vasuki M
Hello all,
Based on the discussion, I have updated the patch to handle the RESET form correctly without modifying psql’s tab-completion APIs.
Both the current database connection and the parsed input tokens are already available via pset.db and the word tokens.The new patch extracts:
the role name from the parsed tokens (prev5_wd), and
the database name from the parsed tokens (prev2_wd),
and uses these to query pg_db_role_setting for variables that are actually set for the specific (role, database) pair.
Literal quoting is now done with PQescapeLiteral(pset.db, …), per libpq conventions, so no new helper functions were needed.
SET
AfterALTER ROLE <role> IN DATABASE <dbname> SET <TAB>
psql completes from Query_for_list_of_set_vars (same behavior as plain ALTER ROLE … SET).
RESET
AfterALTER ROLE <role> IN DATABASE <dbname> RESET <TAB>
psql now completes with the GUC names recorded in pg_db_role_setting for that specific (role,database), plus
ALL.
When no settings exist, onlyALLis suggested.
This mirrors the existing behavior of ALTER DATABASE … RESET.I have attached the patch.
Regards,
Vasuki
On Thu, Nov 27, 2025 at 2:27 PM Ian Lawrence Barwick <barwick@gmail.com> wrote:Hi
I found myself needing to work with ALTER ROLE ... IN DATABASE ... recently
and was annoyed by the lack of tab completion for this, so patch attached.
Regards
Ian Barwick
Вложения
Thanks to Ian and Vasuki for working on tab-completion support for ALTER ROLE ... IN DATABASE.
This is a really good improvement.
Regarding Ian’s patch:
1. The patch applies cleanly and works as expected.
2. Tab-completion for IN DATABASE behaves consistently with existing ALTER ROLE forms.
Suggestion: consider adding regression tests in "src/bin/psql/t/" to cover these new cases.
Regarding Vasuki’s patch:
1. Really nice idea to extend completion for RESET by querying pg_db_role_setting.
2. Use of PQescapeLiteral() (safe quoting) and consistent fallback to ALL is really nice, and if the user falls back to 'ALL' maybe it is a good idea to log it or let the user know of it.
Suggestion: consider adding regression tests in "src/bin/psql/t/" to cover these new cases for SET/RESET.
Overall both patches look great.
Regards,
Surya