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 (pgsql-hackers@postgresql.org) To make changes to your subscription: http://www.postgresql.org/mailpref/pgsql-hackers