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);