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 + \sf[+] function_description linenumber + + + + This command displays the definition of the named function, + in the form of a CREATE OR REPLACE FUNCTION command. + If the form \sf+ is used, the lines are numbered. + + + + If a line number is specified, the display begins at the specified + line of the function. + + + + + \t 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 ||