Sorry,it was an incremental patch. The attached v5 is the fresh patch against Master.
Regards, Vasuki M C-DAC,Chennai
From 57e7f3ce7397467466ae705dbe29c783de87e310 Mon Sep 17 00:00:00 2001 From: Vasuki M <[email protected]> Date: Tue, 6 Jan 2026 14:53:33 +0530 Subject: [PATCH] psql: Add tab-completion support for ALTER ROLE ... IN DATABASE ... SET/RESET forms .This patch extends psql tab completion to support the ALTER ROLE <role> IN DATABASE <dbname> command form. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit After SET, psql completes with the list of configurable GUC variables, matching the behavior of ALTER ROLE … SET. After RESET, psql completes with configuration variables actually set for the given (role, database) pair as recorded in pg_db_role_setting, plus ALL, mirroring ALTER DATABASE … RESET behavior. SQL literal quoting is performed using PQescapeLiteral() via the implicit connection (pset.db). A safety guard ensures a valid connection is present before invoking it, falling back to ALL otherwise. No TAP tests are added, as this change does not introduce new libreadline interactions and SQL-based completion paths are not reliably exercised by the current test harness. Vasuki M --- src/bin/psql/tab-complete.in.c | 70 +++++++++++++++++++++++++++++++++- 1 file changed, 68 insertions(+), 2 deletions(-) diff --git a/src/bin/psql/tab-complete.in.c b/src/bin/psql/tab-complete.in.c index 06edea98f06..3dd46fddb57 100644 --- a/src/bin/psql/tab-complete.in.c +++ b/src/bin/psql/tab-complete.in.c @@ -2536,12 +2536,78 @@ match_previous_words(int pattern_id, else if (Matches("ALTER", "USER|ROLE", MatchAny) && !TailMatches("USER", "MAPPING")) COMPLETE_WITH("BYPASSRLS", "CONNECTION LIMIT", "CREATEDB", "CREATEROLE", - "ENCRYPTED PASSWORD", "INHERIT", "LOGIN", "NOBYPASSRLS", + "ENCRYPTED PASSWORD", "INHERIT","IN DATABASE", "LOGIN", "NOBYPASSRLS", "NOCREATEDB", "NOCREATEROLE", "NOINHERIT", "NOLOGIN", "NOREPLICATION", "NOSUPERUSER", "PASSWORD", "RENAME TO", "REPLICATION", "RESET", "SET", "SUPERUSER", "VALID UNTIL", "WITH"); - + /* ALTER USER,ROLE <name> IN */ + else if (Matches("ALTER", "USER|ROLE", MatchAny, "IN")) + COMPLETE_WITH("DATABASE"); + /* ALTER USER/ROLE <name> IN DATABASE */ + else if (Matches("ALTER", "USER|ROLE", MatchAny, "IN", "DATABASE")) + { + /* ALTER ROLE bob IN DATABASE <TAB> → list databases */ + COMPLETE_WITH_QUERY(Query_for_list_of_databases); + } + /* ALTER USER/ROLE <name> IN DATABASE <dbname> */ + else if (Matches("ALTER", "USER|ROLE", MatchAny, "IN", "DATABASE", MatchAny)) + { + /* ALTER ROLE bob IN DATABASE mydb <TAB> → SET, RESET */ + COMPLETE_WITH("SET", "RESET"); + } + /* ALTER USER/ROLE <name> IN DATABASE <dbname> SET */ + else if (Matches("ALTER", "USER|ROLE", MatchAny, "IN", "DATABASE", MatchAny, "SET")) + { + /* ALTER ROLE bob IN DATABASE mydb SET <TAB> */ + COMPLETE_WITH_QUERY(Query_for_list_of_set_vars); + } + /* ALTER USER/ROLE <name> IN DATABASE <dbname> RESET */ + else if (Matches("ALTER", "USER|ROLE", MatchAny, "IN", "DATABASE", MatchAny, "RESET")) + { + if (!pset.db || PQstatus(pset.db) != CONNECTION_OK) + { + COMPLETE_WITH("ALL"); + } + else + { + /* + * Extract tokens: prev5 = role name prev2 = database name + */ + char *role = prev5_wd; + char *dbname = prev2_wd; + char *q_role; + char *q_dbname; + char *query; + + /* Safe SQL literal quoting using libpq */ + q_role = PQescapeLiteral(pset.db, role, strlen(role)); + q_dbname = PQescapeLiteral(pset.db, dbname, strlen(dbname)); + if (!q_role || !q_dbname) + { + /* If quoting fails, just fall back to ALL */ + if (q_role) + PQfreemem(q_role); + if (q_dbname) + PQfreemem(q_dbname); + COMPLETE_WITH("ALL"); + } + else + { + query = psprintf( + " SELECT split_part(unnest(setconfig), \'=\', 1) " + " FROM pg_db_role_setting " + " WHERE setdatabase = " + " (SELECT oid FROM pg_database WHERE datname = %s) " + " AND setrole = %s::regrole", + q_dbname, q_role); + COMPLETE_WITH_QUERY_PLUS(query, "ALL"); + PQfreemem(q_role); + PQfreemem(q_dbname); + pfree(query); + } + } + } /* ALTER USER,ROLE <name> RESET */ else if (Matches("ALTER", "USER|ROLE", MatchAny, "RESET")) { -- 2.43.0
