Skip to content

Commit b6e0694

Browse files
committed
Add a \sf (show function) command to psql, for those times when you need to
look at a function but don't wish to fire up an editor. Pavel Stehule, reviewed by Jan Urbanski
1 parent 946b078 commit b6e0694

File tree

4 files changed

+152
-8
lines changed

4 files changed

+152
-8
lines changed

doc/src/sgml/ref/psql-ref.sgml

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
<!--
2-
$PostgreSQL: pgsql/doc/src/sgml/ref/psql-ref.sgml,v 1.248 2010/08/12 00:40:59 tgl Exp $
2+
$PostgreSQL: pgsql/doc/src/sgml/ref/psql-ref.sgml,v 1.249 2010/08/14 13:59:49 tgl Exp $
33
PostgreSQL documentation
44
-->
55

@@ -2136,6 +2136,33 @@ lo_import 152801
21362136
</varlistentry>
21372137

21382138

2139+
<varlistentry>
2140+
<term><literal>\sf[+] <replaceable class="parameter">function_description</> </literal></term>
2141+
2142+
<listitem>
2143+
<para>
2144+
This command fetches and shows the definition of the named function,
2145+
in the form of a <command>CREATE OR REPLACE FUNCTION</> command.
2146+
The definition is printed to the current query output channel,
2147+
as set by <command>\o</command>.
2148+
</para>
2149+
2150+
<para>
2151+
The target function can be specified by name alone, or by name
2152+
and arguments, for example <literal>foo(integer, text)</>.
2153+
The argument types must be given if there is more
2154+
than one function of the same name.
2155+
</para>
2156+
2157+
<para>
2158+
If <literal>+</literal> is appended to the command name, then the
2159+
output lines are numbered, with the first line of the function body
2160+
being line 1.
2161+
</para>
2162+
</listitem>
2163+
</varlistentry>
2164+
2165+
21392166
<varlistentry>
21402167
<term><literal>\t</literal></term>
21412168
<listitem>

src/bin/psql/command.c

Lines changed: 117 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
*
44
* Copyright (c) 2000-2010, PostgreSQL Global Development Group
55
*
6-
* $PostgreSQL: pgsql/src/bin/psql/command.c,v 1.226 2010/08/12 00:40:59 tgl Exp $
6+
* $PostgreSQL: pgsql/src/bin/psql/command.c,v 1.227 2010/08/14 13:59:49 tgl Exp $
77
*/
88
#include "postgres_fe.h"
99
#include "command.h"
@@ -1083,6 +1083,121 @@ exec_command(const char *cmd,
10831083
free(opt0);
10841084
}
10851085

1086+
/* \sf -- show a function's source code */
1087+
else if (strcmp(cmd, "sf") == 0 || strcmp(cmd, "sf+") == 0)
1088+
{
1089+
bool show_linenumbers = (strcmp(cmd, "sf+") == 0);
1090+
PQExpBuffer func_buf;
1091+
char *func;
1092+
Oid foid = InvalidOid;
1093+
1094+
func_buf = createPQExpBuffer();
1095+
func = psql_scan_slash_option(scan_state,
1096+
OT_WHOLE_LINE, NULL, true);
1097+
if (!func)
1098+
{
1099+
psql_error("function name is required\n");
1100+
status = PSQL_CMD_ERROR;
1101+
}
1102+
else if (!lookup_function_oid(pset.db, func, &foid))
1103+
{
1104+
/* error already reported */
1105+
status = PSQL_CMD_ERROR;
1106+
}
1107+
else if (!get_create_function_cmd(pset.db, foid, func_buf))
1108+
{
1109+
/* error already reported */
1110+
status = PSQL_CMD_ERROR;
1111+
}
1112+
else
1113+
{
1114+
FILE *output;
1115+
bool is_pager;
1116+
1117+
/* Select output stream: stdout, pager, or file */
1118+
if (pset.queryFout == stdout)
1119+
{
1120+
/* count lines in function to see if pager is needed */
1121+
int lineno = 0;
1122+
const char *lines = func_buf->data;
1123+
1124+
while (*lines != '\0')
1125+
{
1126+
lineno++;
1127+
/* find start of next line */
1128+
lines = strchr(lines, '\n');
1129+
if (!lines)
1130+
break;
1131+
lines++;
1132+
}
1133+
1134+
output = PageOutput(lineno, pset.popt.topt.pager);
1135+
is_pager = true;
1136+
}
1137+
else
1138+
{
1139+
/* use previously set output file, without pager */
1140+
output = pset.queryFout;
1141+
is_pager = false;
1142+
}
1143+
1144+
if (show_linenumbers)
1145+
{
1146+
bool in_header = true;
1147+
int lineno = 0;
1148+
char *lines = func_buf->data;
1149+
1150+
/*
1151+
* lineno "1" should correspond to the first line of the
1152+
* function body. We expect that pg_get_functiondef() will
1153+
* emit that on a line beginning with "AS $function", and that
1154+
* there can be no such line before the real start of the
1155+
* function body.
1156+
*
1157+
* Note that this loop scribbles on func_buf.
1158+
*/
1159+
while (*lines != '\0')
1160+
{
1161+
char *eol;
1162+
1163+
if (in_header && strncmp(lines, "AS $function", 12) == 0)
1164+
in_header = false;
1165+
/* increment lineno only for body's lines */
1166+
if (!in_header)
1167+
lineno++;
1168+
1169+
/* find and mark end of current line */
1170+
eol = strchr(lines, '\n');
1171+
if (eol != NULL)
1172+
*eol = '\0';
1173+
1174+
/* show current line as appropriate */
1175+
if (in_header)
1176+
fprintf(output, " %s\n", lines);
1177+
else
1178+
fprintf(output, "%-7d %s\n", lineno, lines);
1179+
1180+
/* advance to next line, if any */
1181+
if (eol == NULL)
1182+
break;
1183+
lines = ++eol;
1184+
}
1185+
}
1186+
else
1187+
{
1188+
/* just send the function definition to output */
1189+
fputs(func_buf->data, output);
1190+
}
1191+
1192+
if (is_pager)
1193+
ClosePager(output);
1194+
}
1195+
1196+
if (func)
1197+
free(func);
1198+
destroyPQExpBuffer(func_buf);
1199+
}
1200+
10861201
/* \t -- turn off headers and row count */
10871202
else if (strcmp(cmd, "t") == 0)
10881203
{
@@ -1093,7 +1208,6 @@ exec_command(const char *cmd,
10931208
free(opt);
10941209
}
10951210

1096-
10971211
/* \T -- define html <table ...> attributes */
10981212
else if (strcmp(cmd, "T") == 0)
10991213
{
@@ -1667,7 +1781,7 @@ editFile(const char *fname, int lineno)
16671781
editorName, fname);
16681782
#else
16691783
if (lineno > 0)
1670-
sprintf(sys, SYSTEMQUOTE "\"%s\" %s%d \"%s\"" SYSTEMQUOTE,
1784+
sprintf(sys, SYSTEMQUOTE "\"%s\" %s%d \"%s\"" SYSTEMQUOTE,
16711785
editorName, editor_lineno_switch, lineno, fname);
16721786
else
16731787
sprintf(sys, SYSTEMQUOTE "\"%s\" \"%s\"" SYSTEMQUOTE,

src/bin/psql/help.c

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
*
44
* Copyright (c) 2000-2010, PostgreSQL Global Development Group
55
*
6-
* $PostgreSQL: pgsql/src/bin/psql/help.c,v 1.162 2010/08/13 20:56:18 tgl Exp $
6+
* $PostgreSQL: pgsql/src/bin/psql/help.c,v 1.163 2010/08/14 13:59:49 tgl Exp $
77
*/
88
#include "postgres_fe.h"
99

@@ -158,7 +158,7 @@ slashUsage(unsigned short int pager)
158158
{
159159
FILE *output;
160160

161-
output = PageOutput(89, pager);
161+
output = PageOutput(90, pager);
162162

163163
/* if you add/remove a line here, change the row count above */
164164

@@ -220,6 +220,7 @@ slashUsage(unsigned short int pager)
220220
fprintf(output, _(" \\du[+] [PATTERN] list roles (users)\n"));
221221
fprintf(output, _(" \\dv[S+] [PATTERN] list views\n"));
222222
fprintf(output, _(" \\l[+] list all databases\n"));
223+
fprintf(output, _(" \\sf[+] FUNCNAME show a function's definition\n"));
223224
fprintf(output, _(" \\z [PATTERN] same as \\dp\n"));
224225
fprintf(output, "\n");
225226

src/bin/psql/tab-complete.c

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
*
44
* Copyright (c) 2000-2010, PostgreSQL Global Development Group
55
*
6-
* $PostgreSQL: pgsql/src/bin/psql/tab-complete.c,v 1.201 2010/07/20 03:54:19 rhaas Exp $
6+
* $PostgreSQL: pgsql/src/bin/psql/tab-complete.c,v 1.202 2010/08/14 13:59:49 tgl Exp $
77
*/
88

99
/*----------------------------------------------------------------------
@@ -644,7 +644,7 @@ psql_completion(char *text, int start, int end)
644644
"\\f", "\\g", "\\h", "\\help", "\\H", "\\i", "\\l",
645645
"\\lo_import", "\\lo_export", "\\lo_list", "\\lo_unlink",
646646
"\\o", "\\p", "\\password", "\\prompt", "\\pset", "\\q", "\\qecho", "\\r",
647-
"\\set", "\\t", "\\T",
647+
"\\set", "\\sf", "\\t", "\\T",
648648
"\\timing", "\\unset", "\\x", "\\w", "\\z", "\\!", NULL
649649
};
650650

@@ -2517,6 +2517,8 @@ psql_completion(char *text, int start, int end)
25172517

25182518
COMPLETE_WITH_LIST(my_list);
25192519
}
2520+
else if (strcmp(prev_wd, "\\sf") == 0 || strcmp(prev_wd, "\\sf+") == 0)
2521+
COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_functions, NULL);
25202522
else if (strcmp(prev_wd, "\\cd") == 0 ||
25212523
strcmp(prev_wd, "\\e") == 0 || strcmp(prev_wd, "\\edit") == 0 ||
25222524
strcmp(prev_wd, "\\g") == 0 ||

0 commit comments

Comments
 (0)