Re: show() function - updated patch - Mailing list pgsql-patches

From Joe Conway
Subject Re: show() function - updated patch
Date
Msg-id 3D370388.8010206@joeconway.com
Whole thread Raw
In response to Re: show() function  (Peter Eisentraut <peter_e@gmx.net>)
Responses Re: show() function - updated patch  (Bruce Momjian <pgman@candle.pha.pa.us>)
Re: show() function - updated patch  (Bruce Momjian <pgman@candle.pha.pa.us>)
Re: show() function - updated patch  (Tom Lane <tgl@sss.pgh.pa.us>)
List pgsql-patches
Joe Conway wrote:
> 2. This patch includes the same Table Function API fixes that I
>    submitted on July 9:
>
>    http://archives.postgresql.org/pgsql-patches/2002-07/msg00056.php
>
>    Please disregard that one *if* this one is applied. If this one is
>    rejected please go ahead with the July 9th patch.

The July 9th Table Function API patch mentioned above is now in CVS, so
here is an updated version of the guc patch which should apply cleanly
against CVS tip.

If there are no objections, please apply.

Thanks,

Joe
Index: src/backend/commands/explain.c
===================================================================
RCS file: /opt/src/cvs/pgsql/src/backend/commands/explain.c,v
retrieving revision 1.80
diff -c -r1.80 explain.c
*** src/backend/commands/explain.c    20 Jun 2002 20:29:27 -0000    1.80
--- src/backend/commands/explain.c    18 Jul 2002 17:54:10 -0000
***************
*** 15,20 ****
--- 15,21 ----
  #include "access/heapam.h"
  #include "catalog/pg_type.h"
  #include "commands/explain.h"
+ #include "executor/executor.h"
  #include "executor/instrument.h"
  #include "lib/stringinfo.h"
  #include "nodes/print.h"
***************
*** 38,52 ****
      List       *rtable;            /* range table */
  } ExplainState;

- typedef struct TextOutputState
- {
-     TupleDesc    tupdesc;
-     DestReceiver *destfunc;
- } TextOutputState;
-
  static StringInfo Explain_PlanToString(Plan *plan, ExplainState *es);
  static void ExplainOneQuery(Query *query, ExplainStmt *stmt,
!                             TextOutputState *tstate);
  static void explain_outNode(StringInfo str, Plan *plan, Plan *outer_plan,
                              int indent, ExplainState *es);
  static void show_scan_qual(List *qual, bool is_or_qual, const char *qlabel,
--- 39,47 ----
      List       *rtable;            /* range table */
  } ExplainState;

  static StringInfo Explain_PlanToString(Plan *plan, ExplainState *es);
  static void ExplainOneQuery(Query *query, ExplainStmt *stmt,
!                             TupOutputState *tstate);
  static void explain_outNode(StringInfo str, Plan *plan, Plan *outer_plan,
                              int indent, ExplainState *es);
  static void show_scan_qual(List *qual, bool is_or_qual, const char *qlabel,
***************
*** 59,69 ****
  static void show_sort_keys(List *tlist, int nkeys, const char *qlabel,
                             StringInfo str, int indent, ExplainState *es);
  static Node *make_ors_ands_explicit(List *orclauses);
- static TextOutputState *begin_text_output(CommandDest dest, char *title);
- static void do_text_output(TextOutputState *tstate, char *aline);
- static void do_text_output_multiline(TextOutputState *tstate, char *text);
- static void end_text_output(TextOutputState *tstate);
-

  /*
   * ExplainQuery -
--- 54,59 ----
***************
*** 73,88 ****
  ExplainQuery(ExplainStmt *stmt, CommandDest dest)
  {
      Query       *query = stmt->query;
!     TextOutputState *tstate;
      List       *rewritten;
      List       *l;

!     tstate = begin_text_output(dest, "QUERY PLAN");

      if (query->commandType == CMD_UTILITY)
      {
          /* rewriter will not cope with utility statements */
!         do_text_output(tstate, "Utility statements have no plan structure");
      }
      else
      {
--- 63,85 ----
  ExplainQuery(ExplainStmt *stmt, CommandDest dest)
  {
      Query       *query = stmt->query;
!     TupOutputState *tstate;
!     TupleDesc    tupdesc;
      List       *rewritten;
      List       *l;

!     /* need a tuple descriptor representing a single TEXT column */
!     tupdesc = CreateTemplateTupleDesc(1);
!     TupleDescInitEntry(tupdesc, (AttrNumber) 1, "QUERY PLAN",
!                        TEXTOID, -1, 0, false);
!
!     /* prepare for projection of tuples */
!     tstate = begin_tup_output_tupdesc(dest, tupdesc);

      if (query->commandType == CMD_UTILITY)
      {
          /* rewriter will not cope with utility statements */
!         PROJECT_LINE_OF_TEXT("Utility statements have no plan structure");
      }
      else
      {
***************
*** 92,98 ****
          if (rewritten == NIL)
          {
              /* In the case of an INSTEAD NOTHING, tell at least that */
!             do_text_output(tstate, "Query rewrites to nothing");
          }
          else
          {
--- 89,95 ----
          if (rewritten == NIL)
          {
              /* In the case of an INSTEAD NOTHING, tell at least that */
!             PROJECT_LINE_OF_TEXT("Query rewrites to nothing");
          }
          else
          {
***************
*** 102,113 ****
                  ExplainOneQuery(lfirst(l), stmt, tstate);
                  /* put a blank line between plans */
                  if (lnext(l) != NIL)
!                     do_text_output(tstate, "");
              }
          }
      }

!     end_text_output(tstate);
  }

  /*
--- 99,110 ----
                  ExplainOneQuery(lfirst(l), stmt, tstate);
                  /* put a blank line between plans */
                  if (lnext(l) != NIL)
!                     PROJECT_LINE_OF_TEXT("");
              }
          }
      }

!     end_tup_output(tstate);
  }

  /*
***************
*** 115,121 ****
   *      print out the execution plan for one query
   */
  static void
! ExplainOneQuery(Query *query, ExplainStmt *stmt, TextOutputState *tstate)
  {
      Plan       *plan;
      ExplainState *es;
--- 112,118 ----
   *      print out the execution plan for one query
   */
  static void
! ExplainOneQuery(Query *query, ExplainStmt *stmt, TupOutputState *tstate)
  {
      Plan       *plan;
      ExplainState *es;
***************
*** 125,133 ****
      if (query->commandType == CMD_UTILITY)
      {
          if (query->utilityStmt && IsA(query->utilityStmt, NotifyStmt))
!             do_text_output(tstate, "NOTIFY");
          else
!             do_text_output(tstate, "UTILITY");
          return;
      }

--- 122,130 ----
      if (query->commandType == CMD_UTILITY)
      {
          if (query->utilityStmt && IsA(query->utilityStmt, NotifyStmt))
!             PROJECT_LINE_OF_TEXT("NOTIFY");
          else
!             PROJECT_LINE_OF_TEXT("UTILITY");
          return;
      }

***************
*** 192,198 ****
              do_text_output_multiline(tstate, f);
              pfree(f);
              if (es->printCost)
!                 do_text_output(tstate, "");    /* separator line */
          }
      }

--- 189,195 ----
              do_text_output_multiline(tstate, f);
              pfree(f);
              if (es->printCost)
!                 PROJECT_LINE_OF_TEXT("");    /* separator line */
          }
      }

***************
*** 836,914 ****

          return (Node *) make_orclause(args);
      }
- }
-
-
- /*
-  * Functions for sending text to the frontend (or other specified destination)
-  * as though it is a SELECT result.
-  *
-  * We tell the frontend that the table structure is a single TEXT column.
-  */
-
- static TextOutputState *
- begin_text_output(CommandDest dest, char *title)
- {
-     TextOutputState *tstate;
-     TupleDesc    tupdesc;
-
-     tstate = (TextOutputState *) palloc(sizeof(TextOutputState));
-
-     /* need a tuple descriptor representing a single TEXT column */
-     tupdesc = CreateTemplateTupleDesc(1);
-     TupleDescInitEntry(tupdesc, (AttrNumber) 1, title,
-                        TEXTOID, -1, 0, false);
-
-     tstate->tupdesc = tupdesc;
-     tstate->destfunc = DestToFunction(dest);
-
-     (*tstate->destfunc->setup) (tstate->destfunc, (int) CMD_SELECT,
-                                 NULL, tupdesc);
-
-     return tstate;
- }
-
- /* write a single line of text */
- static void
- do_text_output(TextOutputState *tstate, char *aline)
- {
-     HeapTuple    tuple;
-     Datum        values[1];
-     char        nulls[1];
-
-     /* form a tuple and send it to the receiver */
-     values[0] = DirectFunctionCall1(textin, CStringGetDatum(aline));
-     nulls[0] = ' ';
-     tuple = heap_formtuple(tstate->tupdesc, values, nulls);
-     (*tstate->destfunc->receiveTuple) (tuple,
-                                        tstate->tupdesc,
-                                        tstate->destfunc);
-     pfree(DatumGetPointer(values[0]));
-     heap_freetuple(tuple);
- }
-
- /* write a chunk of text, breaking at newline characters */
- /* NB: scribbles on its input! */
- static void
- do_text_output_multiline(TextOutputState *tstate, char *text)
- {
-     while (*text)
-     {
-         char   *eol;
-
-         eol = strchr(text, '\n');
-         if (eol)
-             *eol++ = '\0';
-         else
-             eol = text + strlen(text);
-         do_text_output(tstate, text);
-         text = eol;
-     }
- }
-
- static void
- end_text_output(TextOutputState *tstate)
- {
-     (*tstate->destfunc->cleanup) (tstate->destfunc);
-     pfree(tstate);
  }
--- 833,836 ----
Index: src/backend/executor/execTuples.c
===================================================================
RCS file: /opt/src/cvs/pgsql/src/backend/executor/execTuples.c,v
retrieving revision 1.54
diff -c -r1.54 execTuples.c
*** src/backend/executor/execTuples.c    18 Jul 2002 04:40:30 -0000    1.54
--- src/backend/executor/execTuples.c    18 Jul 2002 17:54:10 -0000
***************
*** 790,792 ****
--- 790,862 ----
      return tuple;
  }

+ /*
+  * Functions for sending tuples to the frontend (or other specified destination)
+  * as though it is a SELECT result. These are used by utility commands that
+  * need to project directly to the destination and don't need or want full
+  * Table Function capability. Currently used by EXPLAIN and SHOW ALL
+  */
+ TupOutputState *
+ begin_tup_output_tupdesc(CommandDest dest, TupleDesc tupdesc)
+ {
+     TupOutputState *tstate;
+
+     tstate = (TupOutputState *) palloc(sizeof(TupOutputState));
+
+     tstate->tupdesc = tupdesc;
+     tstate->destfunc = DestToFunction(dest);
+
+     (*tstate->destfunc->setup) (tstate->destfunc, (int) CMD_SELECT,
+                                 NULL, tupdesc);
+
+     return tstate;
+ }
+
+ /*
+  * write a single tuple
+  *
+  * values is a list of the external C string representations of the values
+  * to be projected.
+  */
+ void
+ do_tup_output(TupOutputState *tstate, char **values)
+ {
+     /* build a tuple from the input strings using the tupdesc */
+     AttInMetadata *attinmeta = TupleDescGetAttInMetadata(tstate->tupdesc);
+     HeapTuple    tuple = BuildTupleFromCStrings(attinmeta, values);
+
+     /* send the tuple to the receiver */
+     (*tstate->destfunc->receiveTuple) (tuple,
+                                        tstate->tupdesc,
+                                        tstate->destfunc);
+     /* clean up */
+     heap_freetuple(tuple);
+ }
+
+ /* write a chunk of text, breaking at newline characters
+  * NB: scribbles on its input!
+  * Should only be used for a single TEXT attribute tupdesc.
+  */
+ void
+ do_text_output_multiline(TupOutputState *tstate, char *text)
+ {
+     while (*text)
+     {
+         char   *eol;
+
+         eol = strchr(text, '\n');
+         if (eol)
+             *eol++ = '\0';
+         else
+             eol = text + strlen(text);
+         do_tup_output(tstate, &text);
+         text = eol;
+     }
+ }
+
+ void
+ end_tup_output(TupOutputState *tstate)
+ {
+     (*tstate->destfunc->cleanup) (tstate->destfunc);
+     pfree(tstate);
+ }
Index: src/backend/utils/misc/guc.c
===================================================================
RCS file: /opt/src/cvs/pgsql/src/backend/utils/misc/guc.c,v
retrieving revision 1.72
diff -c -r1.72 guc.c
*** src/backend/utils/misc/guc.c    18 Jul 2002 02:02:30 -0000    1.72
--- src/backend/utils/misc/guc.c    18 Jul 2002 17:54:10 -0000
***************
*** 23,30 ****
--- 23,32 ----

  #include "access/xlog.h"
  #include "catalog/namespace.h"
+ #include "catalog/pg_type.h"
  #include "commands/async.h"
  #include "commands/variable.h"
+ #include "executor/executor.h"
  #include "fmgr.h"
  #include "libpq/auth.h"
  #include "libpq/pqcomm.h"
***************
*** 826,832 ****


  static int guc_var_compare(const void *a, const void *b);
! static void _ShowOption(struct config_generic *record);


  /*
--- 828,834 ----


  static int guc_var_compare(const void *a, const void *b);
! static char *_ShowOption(struct config_generic *record);


  /*
***************
*** 2168,2173 ****
--- 2170,2226 ----
  }

  /*
+  * SET command wrapped as a SQL callable function.
+  */
+ Datum
+ set_config_by_name(PG_FUNCTION_ARGS)
+ {
+     char   *name;
+     char   *value;
+     char   *new_value;
+     bool    is_local;
+     text   *result_text;
+
+     if (PG_ARGISNULL(0))
+         elog(ERROR, "SET variable name is required");
+
+     /* Get the GUC variable name */
+     name = DatumGetCString(DirectFunctionCall1(textout, PointerGetDatum(PG_GETARG_TEXT_P(0))));
+
+     /* Get the desired value or set to NULL for a reset request */
+     if (PG_ARGISNULL(1))
+         value = NULL;
+     else
+         value = DatumGetCString(DirectFunctionCall1(textout, PointerGetDatum(PG_GETARG_TEXT_P(1))));
+
+     /*
+      * Get the desired state of is_local. Default to false
+      * if provided value is NULL
+      */
+     if (PG_ARGISNULL(2))
+         is_local = false;
+     else
+         is_local = PG_GETARG_BOOL(2);
+
+     /* Note SET DEFAULT (argstring == NULL) is equivalent to RESET */
+     set_config_option(name,
+                       value,
+                       (superuser() ? PGC_SUSET : PGC_USERSET),
+                       PGC_S_SESSION,
+                       is_local,
+                       true);
+
+     /* get the new current value */
+     new_value = GetConfigOptionByName(name);
+
+     /* Convert return string to text */
+     result_text = DatumGetTextP(DirectFunctionCall1(textin, CStringGetDatum(new_value)));
+
+     /* return it */
+     PG_RETURN_TEXT_P(result_text);
+ }
+
+ /*
   * SHOW command
   */
  void
***************
*** 2203,2215 ****
  void
  ShowGUCConfigOption(const char *name)
  {
!     struct config_generic *record;

!     record = find_option(name);
!     if (record == NULL)
!         elog(ERROR, "Option '%s' is not recognized", name);

!     _ShowOption(record);
  }

  /*
--- 2256,2281 ----
  void
  ShowGUCConfigOption(const char *name)
  {
!     TupOutputState *tstate;
!     TupleDesc        tupdesc;
!     CommandDest        dest = whereToSendOutput;
!     char           *value;
!
!     /* need a tuple descriptor representing a single TEXT column */
!     tupdesc = CreateTemplateTupleDesc(1);
!     TupleDescInitEntry(tupdesc, (AttrNumber) 1, (char *) name,
!                        TEXTOID, -1, 0, false);
!
!     /* prepare for projection of tuples */
!     tstate = begin_tup_output_tupdesc(dest, tupdesc);

!     /* Get the value */
!     value = GetConfigOptionByName(name);

!     /* Send it */
!     PROJECT_LINE_OF_TEXT(value);
!
!     end_tup_output(tstate);
  }

  /*
***************
*** 2219,2235 ****
  ShowAllGUCConfig(void)
  {
      int            i;

      for (i = 0; i < num_guc_variables; i++)
      {
!         struct config_generic *conf = guc_variables[i];

!         if ((conf->flags & GUC_NO_SHOW_ALL) == 0)
!             _ShowOption(conf);
      }
  }

! static void
  _ShowOption(struct config_generic *record)
  {
      char        buffer[256];
--- 2285,2399 ----
  ShowAllGUCConfig(void)
  {
      int            i;
+     TupOutputState *tstate;
+     TupleDesc        tupdesc;
+     CommandDest        dest = whereToSendOutput;
+     char           *name;
+     char           *value;
+     char          *values[2];
+
+     /* need a tuple descriptor representing two TEXT columns */
+     tupdesc = CreateTemplateTupleDesc(2);
+     TupleDescInitEntry(tupdesc, (AttrNumber) 1, "name",
+                        TEXTOID, -1, 0, false);
+     TupleDescInitEntry(tupdesc, (AttrNumber) 2, "setting",
+                        TEXTOID, -1, 0, false);
+
+     /* prepare for projection of tuples */
+     tstate = begin_tup_output_tupdesc(dest, tupdesc);

      for (i = 0; i < num_guc_variables; i++)
      {
!         /* Get the next GUC variable name and value */
!         value = GetConfigOptionByNum(i, &name);

!         /* assign to the values array */
!         values[0] = name;
!         values[1] = value;
!
!         /* send it to dest */
!         do_tup_output(tstate, values);
!
!         /*
!          * clean up
!          */
!         /* we always should have a name */
!         pfree(name);
!
!         /* but value can be returned to us as a NULL */
!         if (value != NULL)
!             pfree(value);
      }
+
+     end_tup_output(tstate);
  }

! /*
!  * Return GUC variable value by name
!  */
! char *
! GetConfigOptionByName(const char *name)
! {
!     struct config_generic *record;
!
!     record = find_option(name);
!     if (record == NULL)
!         elog(ERROR, "Option '%s' is not recognized", name);
!
!     return _ShowOption(record);
! }
!
! /*
!  * Return GUC variable value and set varname for a specific
!  * variable by number.
!  */
! char *
! GetConfigOptionByNum(int varnum, char **varname)
! {
!     struct config_generic *conf = guc_variables[varnum];
!
!     *varname = pstrdup(conf->name);
!
!     if ((conf->flags & GUC_NO_SHOW_ALL) == 0)
!         return _ShowOption(conf);
!     else
!         return NULL;
! }
!
! /*
!  * Return the total number of GUC variables
!  */
! int
! GetNumConfigOptions(void)
! {
!     return num_guc_variables;
! }
!
! /*
!  * show_config_by_name - equiv to SHOW X command but implemented as
!  * a function.
!  */
! Datum
! show_config_by_name(PG_FUNCTION_ARGS)
! {
!     char   *varname;
!     char   *varval;
!     text   *result_text;
!
!     /* Get the GUC variable name */
!     varname = DatumGetCString(DirectFunctionCall1(textout, PointerGetDatum(PG_GETARG_TEXT_P(0))));
!
!     /* Get the value */
!     varval = GetConfigOptionByName(varname);
!
!     /* Convert to text */
!     result_text = DatumGetTextP(DirectFunctionCall1(textin, CStringGetDatum(varval)));
!
!     /* return it */
!     PG_RETURN_TEXT_P(result_text);
! }
!
! static char *
  _ShowOption(struct config_generic *record)
  {
      char        buffer[256];
***************
*** 2297,2303 ****
              break;
      }

!     elog(INFO, "%s is %s", record->name, val);
  }


--- 2461,2467 ----
              break;
      }

!     return pstrdup(val);
  }


Index: src/include/catalog/pg_proc.h
===================================================================
RCS file: /opt/src/cvs/pgsql/src/include/catalog/pg_proc.h,v
retrieving revision 1.243
diff -c -r1.243 pg_proc.h
*** src/include/catalog/pg_proc.h    20 Jun 2002 20:29:44 -0000    1.243
--- src/include/catalog/pg_proc.h    18 Jul 2002 17:54:10 -0000
***************
*** 2881,2886 ****
--- 2881,2891 ----
  DATA(insert OID = 2074 (  substring            PGNSP PGUID 14 f f f t f i 3 25 "25 25 25" 100 0 0 100    "select
substring($1,like_escape($2, $3))" - _null_ )); 
  DESCR("substitutes regular expression with escape argument");

+ DATA(insert OID = 2090 (  current_setting    PGNSP PGUID 12 f f f t f s 1 25 "25" 100 0 0 100 show_config_by_name -
_null_)); 
+ DESCR("SHOW X as a function");
+ DATA(insert OID = 2091 (  set_config        PGNSP PGUID 12 f f f f f v 3 25 "25 25 16" 100 0 0 100 set_config_by_name
-_null_ )); 
+ DESCR("SET X as a function");
+
  /* Aggregates (moved here from pg_aggregate for 7.3) */

  DATA(insert OID = 2100 (  avg                PGNSP PGUID 12 t f f f f i 1 1700 "20" 100 0 0 100  aggregate_dummy -
_null_)); 
Index: src/include/executor/executor.h
===================================================================
RCS file: /opt/src/cvs/pgsql/src/include/executor/executor.h,v
retrieving revision 1.69
diff -c -r1.69 executor.h
*** src/include/executor/executor.h    26 Jun 2002 21:58:56 -0000    1.69
--- src/include/executor/executor.h    18 Jul 2002 17:54:10 -0000
***************
*** 121,126 ****
--- 121,145 ----
  extern TupleDesc ExecTypeFromTL(List *targetList);
  extern void SetChangedParamList(Plan *node, List *newchg);

+ typedef struct TupOutputState
+ {
+     TupleDesc    tupdesc;
+     DestReceiver *destfunc;
+ } TupOutputState;
+
+ extern TupOutputState *begin_tup_output_tupdesc(CommandDest dest, TupleDesc tupdesc);
+ extern void do_tup_output(TupOutputState *tstate, char **values);
+ extern void do_text_output_multiline(TupOutputState *tstate, char *text);
+ extern void end_tup_output(TupOutputState *tstate);
+
+ #define PROJECT_LINE_OF_TEXT(text_to_project) \
+     do { \
+         char *values[1]; \
+         values[0] = text_to_project; \
+         do_tup_output(tstate, values); \
+     } while (0)
+
+
  /*
   * prototypes from functions in execUtils.c
   */
Index: src/include/utils/builtins.h
===================================================================
RCS file: /opt/src/cvs/pgsql/src/include/utils/builtins.h,v
retrieving revision 1.186
diff -c -r1.186 builtins.h
*** src/include/utils/builtins.h    20 Jun 2002 20:29:52 -0000    1.186
--- src/include/utils/builtins.h    18 Jul 2002 17:54:10 -0000
***************
*** 633,636 ****
--- 633,640 ----
  extern Datum quote_ident(PG_FUNCTION_ARGS);
  extern Datum quote_literal(PG_FUNCTION_ARGS);

+ /* guc.c */
+ extern Datum show_config_by_name(PG_FUNCTION_ARGS);
+ extern Datum set_config_by_name(PG_FUNCTION_ARGS);
+
  #endif   /* BUILTINS_H */
Index: src/include/utils/guc.h
===================================================================
RCS file: /opt/src/cvs/pgsql/src/include/utils/guc.h,v
retrieving revision 1.17
diff -c -r1.17 guc.h
*** src/include/utils/guc.h    17 May 2002 01:19:19 -0000    1.17
--- src/include/utils/guc.h    18 Jul 2002 17:54:10 -0000
***************
*** 86,91 ****
--- 86,94 ----
                                bool isLocal, bool DoIt);
  extern void ShowGUCConfigOption(const char *name);
  extern void ShowAllGUCConfig(void);
+ extern char *GetConfigOptionByName(const char *name);
+ extern char *GetConfigOptionByNum(int varnum, char **varname);
+ extern int GetNumConfigOptions(void);

  extern void SetPGVariable(const char *name, List *args, bool is_local);
  extern void GetPGVariable(const char *name);

pgsql-patches by date:

Previous
From: Rod Taylor
Date:
Subject: Re: Between Node
Next
From: Bruce Momjian
Date:
Subject: Re: Between Node