]> granicus.if.org Git - postgresql/commitdiff
Add a \sf (show function) command to psql, for those times when you need to
authorTom Lane <tgl@sss.pgh.pa.us>
Sat, 14 Aug 2010 13:59:49 +0000 (13:59 +0000)
committerTom Lane <tgl@sss.pgh.pa.us>
Sat, 14 Aug 2010 13:59:49 +0000 (13:59 +0000)
look at a function but don't wish to fire up an editor.

Pavel Stehule, reviewed by Jan Urbanski

doc/src/sgml/ref/psql-ref.sgml
src/bin/psql/command.c
src/bin/psql/help.c
src/bin/psql/tab-complete.c

index 47b1e99e054a2173eee2f8905dd41592bca99f3f..a93d3d594cf98ac2cdcf4a99dad70f11fbff9b20 100644 (file)
@@ -1,5 +1,5 @@
 <!--
-$PostgreSQL: pgsql/doc/src/sgml/ref/psql-ref.sgml,v 1.248 2010/08/12 00:40:59 tgl Exp $
+$PostgreSQL: pgsql/doc/src/sgml/ref/psql-ref.sgml,v 1.249 2010/08/14 13:59:49 tgl Exp $
 PostgreSQL documentation
 -->
 
@@ -2136,6 +2136,33 @@ lo_import 152801
       </varlistentry>
 
 
+      <varlistentry>
+        <term><literal>\sf[+] <replaceable class="parameter">function_description</> </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.
+         The definition is printed to the current query output channel,
+         as set by <command>\o</command>.
+        </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 <literal>+</literal> is appended to the command name, then the
+         output lines are numbered, with the first line of the function body
+         being line 1.
+        </para>
+        </listitem>
+      </varlistentry>
+
+
       <varlistentry>
         <term><literal>\t</literal></term>
         <listitem>
index 687cbca2ca6e14f39d19a7ccd3e8137a51d6c5ef..e902f5e95c0b03a71f804ad3084d7844793b1fd1 100644 (file)
@@ -3,7 +3,7 @@
  *
  * Copyright (c) 2000-2010, PostgreSQL Global Development Group
  *
- * $PostgreSQL: pgsql/src/bin/psql/command.c,v 1.226 2010/08/12 00:40:59 tgl Exp $
+ * $PostgreSQL: pgsql/src/bin/psql/command.c,v 1.227 2010/08/14 13:59:49 tgl Exp $
  */
 #include "postgres_fe.h"
 #include "command.h"
@@ -1083,6 +1083,121 @@ exec_command(const char *cmd,
                free(opt0);
        }
 
+       /* \sf -- show a function's source code */
+       else if (strcmp(cmd, "sf") == 0 || strcmp(cmd, "sf+") == 0)
+       {
+               bool            show_linenumbers = (strcmp(cmd, "sf+") == 0);
+               PQExpBuffer     func_buf;
+               char       *func;
+               Oid                     foid = InvalidOid;
+
+               func_buf = createPQExpBuffer();
+               func = psql_scan_slash_option(scan_state,
+                                                                         OT_WHOLE_LINE, NULL, true);
+               if (!func)
+               {
+                       psql_error("function name is required\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, func_buf))
+               {
+                       /* error already reported */
+                       status = PSQL_CMD_ERROR;
+               }
+               else
+               {
+                       FILE   *output;
+                       bool    is_pager;
+
+                       /* Select output stream: stdout, pager, or file */
+                       if (pset.queryFout == stdout)
+                       {
+                               /* count lines in function to see if pager is needed */
+                               int                     lineno = 0;
+                               const char *lines = func_buf->data;
+
+                               while (*lines != '\0')
+                               {
+                                       lineno++;
+                                       /* find start of next line */
+                                       lines = strchr(lines, '\n');
+                                       if (!lines)
+                                               break;
+                                       lines++;
+                               }
+
+                               output = PageOutput(lineno, pset.popt.topt.pager);
+                               is_pager = true;
+                       }
+                       else
+                       {
+                               /* use previously set output file, without pager */
+                               output = pset.queryFout;
+                               is_pager = false;
+                       }
+
+                       if (show_linenumbers)
+                       {
+                               bool            in_header = true;
+                               int                     lineno = 0;
+                               char       *lines = func_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", and that
+                                * there can be no such line before the real start of the
+                                * function body.
+                                *
+                                * Note that this loop scribbles on func_buf.
+                                */
+                               while (*lines != '\0')
+                               {
+                                       char   *eol;
+
+                                       if (in_header && strncmp(lines, "AS $function", 12) == 0)
+                                               in_header = false;
+                                       /* increment lineno only for body's lines */
+                                       if (!in_header)
+                                               lineno++;
+
+                                       /* find and mark end of current line */
+                                       eol = strchr(lines, '\n');
+                                       if (eol != NULL)
+                                               *eol = '\0';
+
+                                       /* show current line as appropriate */
+                                       if (in_header)
+                                               fprintf(output, "        %s\n", lines);
+                                       else
+                                               fprintf(output, "%-7d %s\n", lineno, lines);
+
+                                       /* advance to next line, if any */
+                                       if (eol == NULL)
+                                               break;
+                                       lines = ++eol;
+                               }
+                       }
+                       else
+                       {
+                               /* just send the function definition to output */
+                               fputs(func_buf->data, output);
+                       }
+
+                       if (is_pager)
+                               ClosePager(output);
+               }
+
+               if (func)
+                       free(func);
+               destroyPQExpBuffer(func_buf);
+       }
+
        /* \t -- turn off headers and row count */
        else if (strcmp(cmd, "t") == 0)
        {
@@ -1093,7 +1208,6 @@ exec_command(const char *cmd,
                free(opt);
        }
 
-
        /* \T -- define html <table ...> attributes */
        else if (strcmp(cmd, "T") == 0)
        {
@@ -1667,7 +1781,7 @@ editFile(const char *fname, int lineno)
                                editorName, fname);
 #else
        if (lineno > 0)
-               sprintf(sys, SYSTEMQUOTE "\"%s\" %s%d \"%s\"" SYSTEMQUOTE, 
+               sprintf(sys, SYSTEMQUOTE "\"%s\" %s%d \"%s\"" SYSTEMQUOTE,
                                editorName, editor_lineno_switch, lineno, fname);
        else
                sprintf(sys, SYSTEMQUOTE "\"%s\" \"%s\"" SYSTEMQUOTE,
index 822cb59717416c8c8a6564461eb710c4bf26f364..b02f9db9b54aac389e2f6778c7824e8d1aad499a 100644 (file)
@@ -3,7 +3,7 @@
  *
  * Copyright (c) 2000-2010, PostgreSQL Global Development Group
  *
- * $PostgreSQL: pgsql/src/bin/psql/help.c,v 1.162 2010/08/13 20:56:18 tgl Exp $
+ * $PostgreSQL: pgsql/src/bin/psql/help.c,v 1.163 2010/08/14 13:59:49 tgl Exp $
  */
 #include "postgres_fe.h"
 
@@ -158,7 +158,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 */
 
@@ -220,6 +220,7 @@ slashUsage(unsigned short int pager)
        fprintf(output, _("  \\du[+]  [PATTERN]      list roles (users)\n"));
        fprintf(output, _("  \\dv[S+] [PATTERN]      list views\n"));
        fprintf(output, _("  \\l[+]                  list all databases\n"));
+       fprintf(output, _("  \\sf[+] FUNCNAME        show a function's definition\n"));
        fprintf(output, _("  \\z      [PATTERN]      same as \\dp\n"));
        fprintf(output, "\n");
 
index 5368d4ac45c5bf766f14a6d19d5cc694615351f7..0c2d5bc7809019a6d9c326ec1f2bcbe13f46c247 100644 (file)
@@ -3,7 +3,7 @@
  *
  * Copyright (c) 2000-2010, PostgreSQL Global Development Group
  *
- * $PostgreSQL: pgsql/src/bin/psql/tab-complete.c,v 1.201 2010/07/20 03:54:19 rhaas Exp $
+ * $PostgreSQL: pgsql/src/bin/psql/tab-complete.c,v 1.202 2010/08/14 13:59:49 tgl Exp $
  */
 
 /*----------------------------------------------------------------------
@@ -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 (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, "\\cd") == 0 ||
                         strcmp(prev_wd, "\\e") == 0 || strcmp(prev_wd, "\\edit") == 0 ||
                         strcmp(prev_wd, "\\g") == 0 ||