sf.patch
application/octet-stream
Filename: sf.patch
Type: application/octet-stream
Part: 1
Patch
Same data as JSON:
GET /api/v1/attachments/:id/patch
the parsed metadata as JSON — format, series position, per-file stats; never the diff bytes.
API reference →
Format: unified
| File | + | − |
|---|---|---|
| doc/src/sgml/ref/psql-ref.sgml | 17 | 0 |
| src/bin/psql/command.c | 151 | 0 |
| src/bin/psql/help.c | 2 | 1 |
| src/bin/psql/tab-complete.c | 3 | 1 |
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 ||