diff --git a/doc/src/sgml/ref/psql-ref.sgml b/doc/src/sgml/ref/psql-ref.sgml
index 85adf55..7f8ceab 100644
--- a/doc/src/sgml/ref/psql-ref.sgml
+++ b/doc/src/sgml/ref/psql-ref.sgml
@@ -2130,6 +2130,23 @@ lo_import 152801
 
 
       <varlistentry>
+        <term><literal>\sf[+] <replaceable class="parameter">function_description</replaceable> <optional> linenumber </optional> </literal></term>
+
+        <listitem>
+        <para>
+         This command displays the definition of the named function,
+         in the form of a <command>CREATE OR REPLACE FUNCTION</> command.
+         If the form <literal>\sf+</literal> is used, the lines are numbered.
+        </para>
+
+        <para>
+         If a line number is specified, the display begins at the specified
+         line of the function.
+        </para>
+        </listitem>
+      </varlistentry>
+
+      <varlistentry>
         <term><literal>\t</literal></term>
         <listitem>
         <para>
diff --git a/src/bin/psql/command.c b/src/bin/psql/command.c
index 2ee89bc..8ebc9c3 100644
--- a/src/bin/psql/command.c
+++ b/src/bin/psql/command.c
@@ -46,6 +46,7 @@
 #include "input.h"
 #include "large_obj.h"
 #include "mainloop.h"
+#include "pqsignal.h"
 #include "print.h"
 #include "psqlscan.h"
 #include "settings.h"
@@ -1047,6 +1048,156 @@ exec_command(const char *cmd,
 		free(opt0);
 	}
 
+	/*
+	 * \sf -- show the named function
+	 */
+	else if (strcmp(cmd, "sf") == 0 || strcmp(cmd, "sf+") == 0)
+	{
+		int	first_visible_row = -1;
+		bool	with_lno = (cmd[2] == '+');
+
+		if (!query_buf)
+		{
+			psql_error("no query buffer\n");
+			status = PSQL_CMD_ERROR;
+		}
+		else
+		{
+			char	   *func;
+			Oid			foid = InvalidOid;
+
+			func = psql_scan_slash_option(scan_state,
+										  OT_WHOLE_LINE, NULL, true);
+			
+			first_visible_row = strip_lineno_from_funcdesc(func);
+
+			if (first_visible_row == 0)
+			{
+				/* error already reported */
+				status = PSQL_CMD_ERROR;
+			}
+			else if (!func)
+			{
+				/* show error for empty command */
+				psql_error("missing a function name\n");
+				status = PSQL_CMD_ERROR;
+			}
+			else if (!lookup_function_oid(pset.db, func, &foid))
+			{
+				/* error already reported */
+				status = PSQL_CMD_ERROR;
+			}
+			else if (!get_create_function_cmd(pset.db, foid, query_buf))
+			{
+				/* error already reported */
+				status = PSQL_CMD_ERROR;
+			}
+			if (func)
+				free(func);
+		}
+
+		if (status != PSQL_CMD_ERROR)
+		{
+			int	lineno = 0;
+			char   *line;
+			char   *dqtag = NULL;
+			bool	is_header = true;
+			bool	is_body = false;
+			bool	is_footer = false;
+			char   *end_of_line;
+			int	lines;
+			FILE   *output;
+			bool	is_pager;
+			
+			if (pset.queryFout == stdout)
+			{
+				line = query_buf->data;
+				lines = 0;
+				while (*line != '\0')
+				{
+					lines++;
+					end_of_line = strchr(line, '\n');
+					if (!end_of_line)
+						break;
+					line = end_of_line + 1;
+				}
+
+				output = PageOutput(lines, pset.popt.topt.pager);
+				is_pager = output != stdout;
+			}
+			else
+			{
+				output = pset.queryFout;
+				is_pager = false;
+			}
+
+			line = query_buf->data;
+			while (*line != '\0')
+			{
+				/* find next end of line */
+				end_of_line = strchr(line, '\n');
+				if (end_of_line)
+					*end_of_line = '\0';
+
+				if (is_header)
+				{
+					/* detect end of header */
+					dqtag = get_functiondef_dollarquote_tag(line);
+					if (dqtag)
+					{
+						is_header = false;
+						is_body = true;
+						lineno = 1;
+					}
+				}
+				else if (is_body)
+				{
+					lineno++;
+					if (strcmp(line, dqtag) == 0)
+					{
+						is_body = false;
+						is_footer = true;
+					}
+				}
+
+				/* can we show rows? */
+				if (first_visible_row < 0 || (first_visible_row <= lineno))
+				{
+					if (with_lno)
+					{
+						if (is_header || is_footer)
+							fprintf(output, "**** %s", line);
+						else 
+							fprintf(output, "%4d %s", lineno, line);
+					}
+					else
+						fprintf(output, "%s", line);
+
+					/* return back replaced "\n" */
+					if (end_of_line)
+						fprintf(output, "\n");
+				}
+
+				if (end_of_line)
+					line = end_of_line + 1;
+				else
+					break;
+			}
+
+			/* function pg_get_functiondef uses dollar quoted strings always */
+			psql_assert(dqtag != NULL);
+			free(dqtag);
+
+			if (is_pager)
+			{
+				pclose(output);
+#ifndef WIN32
+				pqsignal(SIGPIPE, SIG_DFL);
+#endif
+			}
+		}
+	}
+
 	/* \t -- turn off headers and row count */
 	else if (strcmp(cmd, "t") == 0)
 	{
diff --git a/src/bin/psql/help.c b/src/bin/psql/help.c
index 6a00a1f..9b0645a 100644
--- a/src/bin/psql/help.c
+++ b/src/bin/psql/help.c
@@ -162,7 +162,7 @@ slashUsage(unsigned short int pager)
 {
 	FILE	   *output;
 
-	output = PageOutput(89, pager);
+	output = PageOutput(90, pager);
 
 	/* if you add/remove a line here, change the row count above */
 
@@ -181,6 +181,7 @@ slashUsage(unsigned short int pager)
 #ifdef USE_READLINE
 	fprintf(output, _("  \\s [FILE]              display history or save it to file\n"));
 #endif
+	fprintf(output, _("  \\sf[+] FUNCNAME [LINE] show function definition\n"));
 	fprintf(output, _("  \\w FILE                write query buffer to file\n"));
 	fprintf(output, "\n");
 
diff --git a/src/bin/psql/tab-complete.c b/src/bin/psql/tab-complete.c
index b43c478..1ff3dd9 100644
--- a/src/bin/psql/tab-complete.c
+++ b/src/bin/psql/tab-complete.c
@@ -644,7 +644,7 @@ psql_completion(char *text, int start, int end)
 		"\\f", "\\g", "\\h", "\\help", "\\H", "\\i", "\\l",
 		"\\lo_import", "\\lo_export", "\\lo_list", "\\lo_unlink",
 		"\\o", "\\p", "\\password", "\\prompt", "\\pset", "\\q", "\\qecho", "\\r",
-		"\\set", "\\t", "\\T",
+		"\\set", "\\sf", "\\t", "\\T",
 		"\\timing", "\\unset", "\\x", "\\w", "\\z", "\\!", NULL
 	};
 
@@ -2517,6 +2517,8 @@ psql_completion(char *text, int start, int end)
 
 		COMPLETE_WITH_LIST(my_list);
 	}
+	else if (strncmp(prev_wd, "\\sf", 2) == 0)
+		COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_functions, NULL);
 	else if (strcmp(prev_wd, "\\cd") == 0 ||
 			 strcmp(prev_wd, "\\e") == 0 || strcmp(prev_wd, "\\edit") == 0 ||
 			 strcmp(prev_wd, "\\g") == 0 ||
