Hello
attached updated \sf implementation. It is little bit simplyfied with
support a pager and output forwarding. Formating was updated per Tom's
request.
Regards
Pavel Stehule
>
> BTW, the last I looked, \sf+ was using what I thought to be a quite ugly
> and poorly-considered formatting for the line number. I would suggest
> eight blanks for a header line and "%-7d " as the prefix format for a
> numbered line. The reason for making sure the prefix is 8 columns rather
> than some other width is to not mess up tab-based formatting of the
> function body. I would also prefer a lot more visual separation between
> the line number and the code than "%4d " will offer; and as for the
> stars, they're just useless and distracting.
>
> regards, tom lane
>
*** ./doc/src/sgml/ref/psql-ref.sgml.orig 2010-08-12 02:40:59.000000000 +0200
--- ./doc/src/sgml/ref/psql-ref.sgml 2010-08-12 15:01:04.339404200 +0200
***************
*** 2100,2105 ****
--- 2100,2131 ----
<varlistentry>
+ <term><literal>\sf[+] <optional> <replaceable class="parameter">function_description</> <optional> <replaceable class="parameter">line_number</> </optional> </optional> </literal></term>
+
+ <listitem>
+ <para>
+ This command fetches and shows the definition of the named function,
+ in the form of a <command>CREATE OR REPLACE FUNCTION</> command.
+ If <literal>+</literal> is appended to the command name, then output
+ lines has a line number.
+ </para>
+
+ <para>
+ The target function can be specified by name alone, or by name
+ and arguments, for example <literal>foo(integer, text)</>.
+ The argument types must be given if there is more
+ than one function of the same name.
+ </para>
+
+ <para>
+ If a line number is specified, <application>psql</application> will
+ show the specified line as first line. Previous lines are skiped.
+ </para>
+ </listitem>
+ </varlistentry>
+
+
+ <varlistentry>
<term><literal>\set [ <replaceable class="parameter">name</replaceable> [ <replaceable class="parameter">value</replaceable> [ ... ] ] ]</literal></term>
<listitem>
*** ./src/bin/psql/command.c.orig 2010-08-12 02:40:59.000000000 +0200
--- ./src/bin/psql/command.c 2010-08-12 14:39:22.334403954 +0200
***************
*** 32,37 ****
--- 32,38 ----
#ifdef USE_SSL
#include <openssl/ssl.h>
#endif
+ #include <signal.h>
#include "portability/instr_time.h"
***************
*** 46,51 ****
--- 47,53 ----
#include "input.h"
#include "large_obj.h"
#include "mainloop.h"
+ #include "pqsignal.h"
#include "print.h"
#include "psqlscan.h"
#include "settings.h"
***************
*** 1083,1088 ****
--- 1085,1232 ----
free(opt0);
}
+ /* \sf = show a function source code */
+ else if (strcmp(cmd, "sf") == 0 || strcmp(cmd, "sf+") == 0)
+ {
+ bool show_lineno;
+ int first_visible_line = -1;
+
+ show_lineno = (strcmp(cmd, "sf+") == 0);
+
+ 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_line = strip_lineno_from_funcdesc(func);
+ if (first_visible_line == 0)
+ {
+ /* error already reported */
+ status = PSQL_CMD_ERROR;
+ }
+ else if (!func)
+ {
+ 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)
+ {
+ FILE *output;
+ bool is_pager = false;
+
+ /*
+ * Count a lines in function definition - it's used for opening
+ * a pager. Get a output stream - stdout, pager or forwarded output.
+ */
+ if (pset.queryFout == stdout)
+ {
+ int lc = 0;
+ const char *lines = query_buf->data;
+
+ while (*lines != '\0')
+ {
+ lc++;
+ /* find start of next line */
+ lines = strchr(lines, '\n');
+ if (!lines)
+ break;
+ lines++;
+ }
+
+ output = PageOutput(lc, pset.popt.topt.pager);
+ is_pager = output != stdout;
+ }
+ else
+ {
+ /* use a prepared query output, pager isn't activated */
+ output = pset.queryFout;
+ is_pager = false;
+ }
+
+ if (first_visible_line > 0 || show_lineno)
+ {
+ bool is_header = true; /* true, when header lines is processed */
+ int lineno = 0;
+ char *lines = query_buf->data;
+
+ /*
+ * lineno "1" should correspond to the first line of the function
+ * body. We expect that pg_get_functiondef() will emit that on a line
+ * beginning with "AS $function" is real start of the function body.
+ */
+ while (*lines != '\0')
+ {
+ char *eol;
+
+ if (is_header && strncmp(lines, "AS $function", 12) == 0)
+ is_header = false;
+
+ /* increment lineno only for body's lines */
+ if (!is_header)
+ lineno++;
+ /* find a end of current line */
+ eol = strchr(lines, '\n');
+ /* show a current line, when it is desirable */
+ if (first_visible_line == -1 || lineno >= first_visible_line)
+ {
+ /* disjoin a current line from a next line */
+ if (eol != NULL)
+ *eol = '\0';
+ if (!show_lineno)
+ fprintf(output, "%s", lines);
+ else if (is_header)
+ fprintf(output, " %s", lines);
+ else
+ fprintf(output, "%-7d %s", lineno, lines);
+ /* print a replaced \n char */
+ if (eol)
+ fprintf(output, "\n");
+ }
+ /* leave when there are not a next line */
+ if (!eol)
+ break;
+ /* move to next line */
+ lines = ++eol;
+ }
+ }
+ else
+ {
+ /* just send a function definition to output */
+ fprintf(output, "%s", query_buf->data);
+ }
+
+ 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)
{
*** ./src/bin/psql/help.c.orig 2010-08-12 02:40:59.000000000 +0200
--- ./src/bin/psql/help.c 2010-08-12 14:53:25.491278641 +0200
***************
*** 162,168 ****
{
FILE *output;
! output = PageOutput(89, pager);
/* if you add/remove a line here, change the row count above */
--- 162,168 ----
{
FILE *output;
! output = PageOutput(90, pager);
/* if you add/remove a line here, change the row count above */
***************
*** 223,228 ****
--- 223,229 ----
fprintf(output, _(" \\dT[S+] [PATTERN] list data types\n"));
fprintf(output, _(" \\du[+] [PATTERN] list roles (users)\n"));
fprintf(output, _(" \\dv[S+] [PATTERN] list views\n"));
+ fprintf(output, _(" \\sf[+] FUNCNAME [LINE]] show the function definition\n"));
fprintf(output, _(" \\l[+] list all databases\n"));
fprintf(output, _(" \\z [PATTERN] same as \\dp\n"));
fprintf(output, "\n");
*** ./src/bin/psql/tab-complete.c.orig 2010-07-20 05:54:19.000000000 +0200
--- ./src/bin/psql/tab-complete.c 2010-08-12 14:49:19.490403596 +0200
***************
*** 644,650 ****
"\\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",
"\\timing", "\\unset", "\\x", "\\w", "\\z", "\\!", NULL
};
--- 644,650 ----
"\\f", "\\g", "\\h", "\\help", "\\H", "\\i", "\\l",
"\\lo_import", "\\lo_export", "\\lo_list", "\\lo_unlink",
"\\o", "\\p", "\\password", "\\prompt", "\\pset", "\\q", "\\qecho", "\\r",
! "\\set", "\\sf", "\\t", "\\T",
"\\timing", "\\unset", "\\x", "\\w", "\\z", "\\!", NULL
};
***************
*** 2501,2506 ****
--- 2501,2508 ----
else if (strcmp(prev_wd, "\\ef") == 0)
COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_functions, NULL);
+ else if (strcmp(prev_wd, "\\sf") == 0 || strcmp(prev_wd, "\\sf+") == 0)
+ COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_functions, NULL);
else if (strcmp(prev_wd, "\\encoding") == 0)
COMPLETE_WITH_QUERY(Query_for_list_of_encodings);
--
Sent via pgsql-hackers mailing list ([email protected])
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers