From c466e3d5a7ac2e1f1b110e6f98e0927a519d1696 Mon Sep 17 00:00:00 2001
From: Florents Tselai <florents.tselai@gmail.com>
Date: Sat, 25 Oct 2025 07:34:30 +0300
Subject: [PATCH v3] psql: Add %S prompt escape to display current search_path

This adds a new prompt escape sequence, %S, which expands to the
current value of the session's search_path as reported by libpq via
PQparameterStatus().

If the connected server does not report a search_path parameter
(e.g., servers older than v18), or if the client is not connected,
%S displays a question mark (?).  An empty but valid search_path ("")
is shown as empty.
---
 doc/src/sgml/ref/psql-ref.sgml | 15 +++++++++++++++
 src/bin/psql/common.c          | 13 +++++++++++++
 src/bin/psql/common.h          |  2 ++
 src/bin/psql/prompt.c          |  4 ++++
 4 files changed, 34 insertions(+)

diff --git a/doc/src/sgml/ref/psql-ref.sgml b/doc/src/sgml/ref/psql-ref.sgml
index 1a339600bc4..9a207d117ff 100644
--- a/doc/src/sgml/ref/psql-ref.sgml
+++ b/doc/src/sgml/ref/psql-ref.sgml
@@ -4979,6 +4979,21 @@ testdb=&gt; <userinput>INSERT INTO my_table VALUES (:'content');</userinput>
         <listitem><para>The name of the service.</para></listitem>
       </varlistentry>
 
+     <varlistentry id="app-psql-prompting-S">
+      <term><literal>%S</literal></term>
+      <listitem>
+       <para>
+        The current <literal>search_path</literal>
+        (see <xref linkend="ddl-schemas-path"/>). If the connected server
+        does not report a <literal>search_path</literal> via
+        <literal>ParameterStatus</literal> (e.g., older servers), or the
+        session is not connected, a question mark (<literal>?</literal>)
+        is shown. Note that an empty string is a valid
+        <literal>search_path</literal> and will be displayed as empty.
+       </para>
+      </listitem>
+     </varlistentry>
+
       <varlistentry id="app-psql-prompting-slash">
         <term><literal>%/</literal></term>
         <listitem><para>The name of the current database.</para></listitem>
diff --git a/src/bin/psql/common.c b/src/bin/psql/common.c
index cd329ade12b..4109496d2ad 100644
--- a/src/bin/psql/common.c
+++ b/src/bin/psql/common.c
@@ -2705,3 +2705,16 @@ recognized_connection_string(const char *connstr)
 {
 	return uri_prefix_length(connstr) != 0 || strchr(connstr, '=') != NULL;
 }
+
+/* Return current search_path or "?" if unknown/not connected. */
+const char *
+session_search_path(void)
+{
+	const char *val;
+
+	if (!pset.db)
+		return "?";
+
+	val = PQparameterStatus(pset.db, "search_path");
+	return (val == NULL) ? "?" : val; /* empty "" is valid and returned as-is */
+}
diff --git a/src/bin/psql/common.h b/src/bin/psql/common.h
index 64762ab9817..5a78ed6b43c 100644
--- a/src/bin/psql/common.h
+++ b/src/bin/psql/common.h
@@ -46,4 +46,6 @@ extern void clean_extended_state(void);
 
 extern bool recognized_connection_string(const char *connstr);
 
+extern const char *session_search_path(void);
+
 #endif							/* COMMON_H */
diff --git a/src/bin/psql/prompt.c b/src/bin/psql/prompt.c
index b08d7328fbf..18942c8ab34 100644
--- a/src/bin/psql/prompt.c
+++ b/src/bin/psql/prompt.c
@@ -176,6 +176,10 @@ get_prompt(promptStatus_t status, ConditionalStack cstack)
 							strlcpy(buf, service_name, sizeof(buf));
 					}
 					break;
+					/* current search_path, or "?" if not reported by the server */
+				case 'S':
+					strlcpy(buf, session_search_path(), sizeof(buf));
+					break;
 					/* backend pid */
 				case 'p':
 					if (pset.db)
-- 
2.49.0

