From 076fe1e55aed2dc878853723883ee245e8db5451 Mon Sep 17 00:00:00 2001 From: Vasuki M Date: Tue, 6 Jan 2026 12:07:15 +0530 Subject: [PATCH] [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 IN DATABASE 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 | 66 +++++++++++++++++++--------------- 1 file changed, 37 insertions(+), 29 deletions(-) diff --git a/src/bin/psql/tab-complete.in.c b/src/bin/psql/tab-complete.in.c index 5174d025531..c5fc2354797 100644 --- a/src/bin/psql/tab-complete.in.c +++ b/src/bin/psql/tab-complete.in.c @@ -2566,40 +2566,48 @@ match_previous_words(int pattern_id, /* ALTER USER/ROLE IN DATABASE RESET */ else if (Matches("ALTER", "USER|ROLE", MatchAny, "IN", "DATABASE", MatchAny, "RESET")) { - /* - * 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 (!pset.db || PQstatus(pset.db) != CONNECTION_OK) { - /* 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); + /* + * 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); + } + } } -- 2.43.0