> 2. This patch includes the same Table Function API fixes that I
authorBruce Momjian
Sat, 20 Jul 2002 05:49:28 +0000 (05:49 +0000)
committerBruce Momjian
Sat, 20 Jul 2002 05:49:28 +0000 (05:49 +0000)
>    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.

Joe Conway

src/backend/commands/explain.c
src/backend/executor/execTuples.c
src/backend/utils/misc/guc.c
src/include/catalog/pg_proc.h
src/include/executor/executor.h
src/include/utils/builtins.h
src/include/utils/guc.h

index 2c90df205afcc1e9aee8adcc448634ee0f3c071d..72acab0f1ebefee79b6c326cde65fcfa59904a09 100644 (file)
@@ -5,7 +5,7 @@
  * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994-5, Regents of the University of California
  *
- * $Header: /cvsroot/pgsql/src/backend/commands/explain.c,v 1.81 2002/07/20 05:16:57 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/commands/explain.c,v 1.82 2002/07/20 05:49:27 momjian Exp $
  *
  */
 
@@ -15,6 +15,7 @@
 #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,15 +39,9 @@ typedef struct ExplainState
    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);
+                           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,11 +54,6 @@ static void show_upper_qual(List *qual, const char *qlabel,
 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 -
@@ -73,16 +63,23 @@ void
 ExplainQuery(ExplainStmt *stmt, CommandDest dest)
 {
    Query      *query = stmt->query;
-   TextOutputState *tstate;
+   TupOutputState *tstate;
+   TupleDesc   tupdesc;
    List       *rewritten;
    List       *l;
 
-   tstate = begin_text_output(dest, "QUERY PLAN");
+   /* 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 */
-       do_text_output(tstate, "Utility statements have no plan structure");
+       PROJECT_LINE_OF_TEXT("Utility statements have no plan structure");
    }
    else
    {
@@ -92,7 +89,7 @@ ExplainQuery(ExplainStmt *stmt, CommandDest dest)
        if (rewritten == NIL)
        {
            /* In the case of an INSTEAD NOTHING, tell at least that */
-           do_text_output(tstate, "Query rewrites to nothing");
+           PROJECT_LINE_OF_TEXT("Query rewrites to nothing");
        }
        else
        {
@@ -102,12 +99,12 @@ ExplainQuery(ExplainStmt *stmt, CommandDest dest)
                ExplainOneQuery(lfirst(l), stmt, tstate);
                /* put a blank line between plans */
                if (lnext(l) != NIL)
-                   do_text_output(tstate, "");
+                   PROJECT_LINE_OF_TEXT("");
            }
        }
    }
 
-   end_text_output(tstate);
+   end_tup_output(tstate);
 }
 
 /*
@@ -115,7 +112,7 @@ ExplainQuery(ExplainStmt *stmt, CommandDest dest)
  *   print out the execution plan for one query
  */
 static void
-ExplainOneQuery(Query *query, ExplainStmt *stmt, TextOutputState *tstate)
+ExplainOneQuery(Query *query, ExplainStmt *stmt, TupOutputState *tstate)
 {
    Plan       *plan;
    ExplainState *es;
@@ -125,9 +122,9 @@ ExplainOneQuery(Query *query, ExplainStmt *stmt, TextOutputState *tstate)
    if (query->commandType == CMD_UTILITY)
    {
        if (query->utilityStmt && IsA(query->utilityStmt, NotifyStmt))
-           do_text_output(tstate, "NOTIFY");
+           PROJECT_LINE_OF_TEXT("NOTIFY");
        else
-           do_text_output(tstate, "UTILITY");
+           PROJECT_LINE_OF_TEXT("UTILITY");
        return;
    }
 
@@ -192,7 +189,7 @@ ExplainOneQuery(Query *query, ExplainStmt *stmt, TextOutputState *tstate)
            do_text_output_multiline(tstate, f);
            pfree(f);
            if (es->printCost)
-               do_text_output(tstate, ""); /* separator line */
+               PROJECT_LINE_OF_TEXT("");   /* separator line */
        }
    }
 
@@ -837,78 +834,3 @@ make_ors_ands_explicit(List *orclauses)
        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, WITHOUTOID);
-   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);
-}
index 5124bd023fb826e8c63407d9ba1320901bf02e9d..06a784ce26d1f92d39395473ab064542ad46fb8f 100644 (file)
@@ -15,7 +15,7 @@
  *
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/backend/executor/execTuples.c,v 1.55 2002/07/20 05:16:57 momjian Exp $
+ *   $Header: /cvsroot/pgsql/src/backend/executor/execTuples.c,v 1.56 2002/07/20 05:49:27 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -791,3 +791,73 @@ BuildTupleFromCStrings(AttInMetadata *attinmeta, char **values)
    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 482423f805f5e3e526ec253a7c334c7318583df2..d63d603b1dbe435c7edae5b15f7df27058d19cbe 100644 (file)
@@ -5,7 +5,7 @@
  * command, configuration file, and command line options.
  * See src/backend/utils/misc/README for more information.
  *
- * $Header: /cvsroot/pgsql/src/backend/utils/misc/guc.c,v 1.72 2002/07/18 02:02:30 ishii Exp $
+ * $Header: /cvsroot/pgsql/src/backend/utils/misc/guc.c,v 1.73 2002/07/20 05:49:27 momjian Exp $
  *
  * Copyright 2000 by PostgreSQL Global Development Group
  * Written by Peter Eisentraut .
 
 #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,7 +828,7 @@ static char *guc_string_workspace; /* for avoiding memory leaks */
 
 
 static int guc_var_compare(const void *a, const void *b);
-static void _ShowOption(struct config_generic *record);
+static char *_ShowOption(struct config_generic *record);
 
 
 /*
@@ -2167,6 +2169,57 @@ SetPGVariable(const char *name, List *args, bool is_local)
                      true);
 }
 
+/*
+ * 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
  */
@@ -2203,13 +2256,26 @@ ResetPGVariable(const char *name)
 void
 ShowGUCConfigOption(const char *name)
 {
-   struct config_generic *record;
+   TupOutputState *tstate;
+   TupleDesc       tupdesc;
+   CommandDest     dest = whereToSendOutput;
+   char           *value;
 
-   record = find_option(name);
-   if (record == NULL)
-       elog(ERROR, "Option '%s' is not recognized", name);
+   /* 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);
 
-   _ShowOption(record);
+   /* Get the value */
+   value = GetConfigOptionByName(name);
+
+   /* Send it */
+   PROJECT_LINE_OF_TEXT(value);
+
+   end_tup_output(tstate);
 }
 
 /*
@@ -2219,17 +2285,115 @@ void
 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++)
    {
-       struct config_generic *conf = 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;
 
-       if ((conf->flags & GUC_NO_SHOW_ALL) == 0)
-           _ShowOption(conf);
+       /* 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);
 }
 
-static void
+/*
+ * 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,7 +2461,7 @@ _ShowOption(struct config_generic *record)
            break;
    }
 
-   elog(INFO, "%s is %s", record->name, val);
+   return pstrdup(val);
 }
 
 
index c84ac13a9591d7e9c11f4933d767eb28bf264c2b..49667819453c80e988c1732db780640d16b88b45 100644 (file)
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: pg_proc.h,v 1.244 2002/07/18 23:11:30 petere Exp $
+ * $Id: pg_proc.h,v 1.245 2002/07/20 05:49:27 momjian Exp $
  *
  * NOTES
  *   The script catalog/genbki.sh reads this file and generates .bki
@@ -2881,6 +2881,11 @@ DESCR("substitutes regular expression");
 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 427c146a574c0caa1bbe7e0843c62364bf789a39..5b121546d960529ef7d11bc1fe9c9f7590a06236 100644 (file)
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: executor.h,v 1.70 2002/07/20 05:16:59 momjian Exp $
+ * $Id: executor.h,v 1.71 2002/07/20 05:49:28 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -121,6 +121,25 @@ extern TupleTableSlot *ExecInitNullTupleSlot(EState *estate,
 extern TupleDesc ExecTypeFromTL(List *targetList, hasoid_t withoid);
 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 d79b1c6dcb3025dd152618ec87893deb2fcde5bd..02a537ca4ee63be6aed52dc70e4a84ee1d09be56 100644 (file)
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: builtins.h,v 1.186 2002/06/20 20:29:52 momjian Exp $
+ * $Id: builtins.h,v 1.187 2002/07/20 05:49:28 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -633,4 +633,8 @@ extern int32 type_maximum_size(Oid type_oid, int32 typemod);
 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 ce1b10be839ea551dfaa004a09924fcb51468d5d..35c56eba76e826008f24c2a529f27c523115b834 100644 (file)
@@ -4,7 +4,7 @@
  * External declarations pertaining to backend/utils/misc/guc.c and
  * backend/utils/misc/guc-file.l
  *
- * $Id: guc.h,v 1.17 2002/05/17 01:19:19 tgl Exp $
+ * $Id: guc.h,v 1.18 2002/07/20 05:49:28 momjian Exp $
  */
 #ifndef GUC_H
 #define GUC_H
@@ -86,6 +86,9 @@ extern bool set_config_option(const char *name, const char *value,
                              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);