aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/backend/commands/define.c13
-rw-r--r--src/backend/commands/explain.c171
-rw-r--r--src/backend/commands/prepare.c16
-rw-r--r--src/backend/nodes/copyfuncs.c5
-rw-r--r--src/backend/nodes/equalfuncs.c5
-rw-r--r--src/backend/parser/gram.y77
-rw-r--r--src/backend/tcop/utility.c14
-rw-r--r--src/include/commands/explain.h38
-rw-r--r--src/include/commands/prepare.h9
-rw-r--r--src/include/nodes/parsenodes.h5
10 files changed, 218 insertions, 135 deletions
diff --git a/src/backend/commands/define.c b/src/backend/commands/define.c
index 009dcfd17d8..2fd919dd546 100644
--- a/src/backend/commands/define.c
+++ b/src/backend/commands/define.c
@@ -9,7 +9,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/commands/define.c,v 1.104 2009/04/04 21:12:31 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/commands/define.c,v 1.105 2009/07/26 23:34:17 tgl Exp $
*
* DESCRIPTION
* The "DefineFoo" routines take the parse tree and pick out the
@@ -133,7 +133,7 @@ defGetBoolean(DefElem *def)
return true;
/*
- * Allow 0, 1, "true", "false"
+ * Allow 0, 1, "true", "false", "on", "off"
*/
switch (nodeTag(def->arg))
{
@@ -153,11 +153,18 @@ defGetBoolean(DefElem *def)
{
char *sval = defGetString(def);
+ /*
+ * The set of strings accepted here should match up with
+ * the grammar's opt_boolean production.
+ */
if (pg_strcasecmp(sval, "true") == 0)
return true;
if (pg_strcasecmp(sval, "false") == 0)
return false;
-
+ if (pg_strcasecmp(sval, "on") == 0)
+ return true;
+ if (pg_strcasecmp(sval, "off") == 0)
+ return false;
}
break;
}
diff --git a/src/backend/commands/explain.c b/src/backend/commands/explain.c
index 899f2581bc4..1388c8dd42f 100644
--- a/src/backend/commands/explain.c
+++ b/src/backend/commands/explain.c
@@ -7,7 +7,7 @@
* Portions Copyright (c) 1994-5, Regents of the University of California
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/commands/explain.c,v 1.187 2009/07/24 21:08:42 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/commands/explain.c,v 1.188 2009/07/26 23:34:17 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -16,6 +16,7 @@
#include "access/xact.h"
#include "catalog/pg_constraint.h"
#include "catalog/pg_type.h"
+#include "commands/defrem.h"
#include "commands/explain.h"
#include "commands/prepare.h"
#include "commands/trigger.h"
@@ -40,20 +41,8 @@ ExplainOneQuery_hook_type ExplainOneQuery_hook = NULL;
explain_get_index_name_hook_type explain_get_index_name_hook = NULL;
-typedef struct ExplainState
-{
- StringInfo str; /* output buffer */
- /* options */
- bool printTList; /* print plan targetlists */
- bool printAnalyze; /* print actual times */
- /* other states */
- PlannedStmt *pstmt; /* top of plan */
- List *rtable; /* range table */
-} ExplainState;
-
-static void ExplainOneQuery(Query *query, ExplainStmt *stmt,
- const char *queryString,
- ParamListInfo params, TupOutputState *tstate);
+static void ExplainOneQuery(Query *query, ExplainState *es,
+ const char *queryString, ParamListInfo params);
static void report_triggers(ResultRelInfo *rInfo, bool show_relname,
StringInfo buf);
static double elapsed_time(instr_time *starttime);
@@ -84,11 +73,33 @@ void
ExplainQuery(ExplainStmt *stmt, const char *queryString,
ParamListInfo params, DestReceiver *dest)
{
+ ExplainState es;
Oid *param_types;
int num_params;
TupOutputState *tstate;
List *rewritten;
- ListCell *l;
+ ListCell *lc;
+
+ /* Initialize ExplainState. */
+ ExplainInitState(&es);
+
+ /* Parse options list. */
+ foreach(lc, stmt->options)
+ {
+ DefElem *opt = (DefElem *) lfirst(lc);
+
+ if (strcmp(opt->defname, "analyze") == 0)
+ es.analyze = defGetBoolean(opt);
+ else if (strcmp(opt->defname, "verbose") == 0)
+ es.verbose = defGetBoolean(opt);
+ else if (strcmp(opt->defname, "costs") == 0)
+ es.costs = defGetBoolean(opt);
+ else
+ ereport(ERROR,
+ (errcode(ERRCODE_SYNTAX_ERROR),
+ errmsg("unrecognized EXPLAIN option \"%s\"",
+ opt->defname)));
+ }
/* Convert parameter type data to the form parser wants */
getParamListTypes(params, &param_types, &num_params);
@@ -106,28 +117,44 @@ ExplainQuery(ExplainStmt *stmt, const char *queryString,
rewritten = pg_analyze_and_rewrite((Node *) copyObject(stmt->query),
queryString, param_types, num_params);
- /* prepare for projection of tuples */
- tstate = begin_tup_output_tupdesc(dest, ExplainResultDesc(stmt));
-
if (rewritten == NIL)
{
/* In the case of an INSTEAD NOTHING, tell at least that */
- do_text_output_oneline(tstate, "Query rewrites to nothing");
+ appendStringInfoString(es.str, "Query rewrites to nothing\n");
}
else
{
+ ListCell *l;
+
/* Explain every plan */
foreach(l, rewritten)
{
- ExplainOneQuery((Query *) lfirst(l), stmt,
- queryString, params, tstate);
+ ExplainOneQuery((Query *) lfirst(l), &es, queryString, params);
/* put a blank line between plans */
if (lnext(l) != NULL)
- do_text_output_oneline(tstate, "");
+ appendStringInfoChar(es.str, '\n');
}
}
+ /* output tuples */
+ tstate = begin_tup_output_tupdesc(dest, ExplainResultDesc(stmt));
+ do_text_output_multiline(tstate, es.str->data);
end_tup_output(tstate);
+
+ pfree(es.str->data);
+}
+
+/*
+ * Initialize ExplainState.
+ */
+void
+ExplainInitState(ExplainState *es)
+{
+ /* Set default options. */
+ memset(es, 0, sizeof(ExplainState));
+ es->costs = true;
+ /* Prepare output buffer. */
+ es->str = makeStringInfo();
}
/*
@@ -151,20 +178,19 @@ ExplainResultDesc(ExplainStmt *stmt)
* print out the execution plan for one Query
*/
static void
-ExplainOneQuery(Query *query, ExplainStmt *stmt, const char *queryString,
- ParamListInfo params, TupOutputState *tstate)
+ExplainOneQuery(Query *query, ExplainState *es,
+ const char *queryString, ParamListInfo params)
{
/* planner will not cope with utility statements */
if (query->commandType == CMD_UTILITY)
{
- ExplainOneUtility(query->utilityStmt, stmt,
- queryString, params, tstate);
+ ExplainOneUtility(query->utilityStmt, es, queryString, params);
return;
}
/* if an advisor plugin is present, let it manage things */
if (ExplainOneQuery_hook)
- (*ExplainOneQuery_hook) (query, stmt, queryString, params, tstate);
+ (*ExplainOneQuery_hook) (query, es, queryString, params);
else
{
PlannedStmt *plan;
@@ -173,7 +199,7 @@ ExplainOneQuery(Query *query, ExplainStmt *stmt, const char *queryString,
plan = pg_plan_query(query, 0, params);
/* run it (if needed) and produce output */
- ExplainOnePlan(plan, stmt, queryString, params, tstate);
+ ExplainOnePlan(plan, es, queryString, params);
}
}
@@ -187,21 +213,20 @@ ExplainOneQuery(Query *query, ExplainStmt *stmt, const char *queryString,
* EXPLAIN EXECUTE case
*/
void
-ExplainOneUtility(Node *utilityStmt, ExplainStmt *stmt,
- const char *queryString, ParamListInfo params,
- TupOutputState *tstate)
+ExplainOneUtility(Node *utilityStmt, ExplainState *es,
+ const char *queryString, ParamListInfo params)
{
if (utilityStmt == NULL)
return;
if (IsA(utilityStmt, ExecuteStmt))
- ExplainExecuteQuery((ExecuteStmt *) utilityStmt, stmt,
- queryString, params, tstate);
+ ExplainExecuteQuery((ExecuteStmt *) utilityStmt, es,
+ queryString, params);
else if (IsA(utilityStmt, NotifyStmt))
- do_text_output_oneline(tstate, "NOTIFY");
+ appendStringInfoString(es->str, "NOTIFY\n");
else
- do_text_output_oneline(tstate,
- "Utility statements have no plan structure");
+ appendStringInfoString(es->str,
+ "Utility statements have no plan structure\n");
}
/*
@@ -219,14 +244,12 @@ ExplainOneUtility(Node *utilityStmt, ExplainStmt *stmt,
* to call it.
*/
void
-ExplainOnePlan(PlannedStmt *plannedstmt, ExplainStmt *stmt,
- const char *queryString, ParamListInfo params,
- TupOutputState *tstate)
+ExplainOnePlan(PlannedStmt *plannedstmt, ExplainState *es,
+ const char *queryString, ParamListInfo params)
{
QueryDesc *queryDesc;
instr_time starttime;
double totaltime = 0;
- StringInfoData buf;
int eflags;
/*
@@ -238,17 +261,16 @@ ExplainOnePlan(PlannedStmt *plannedstmt, ExplainStmt *stmt,
/* Create a QueryDesc requesting no output */
queryDesc = CreateQueryDesc(plannedstmt, queryString,
GetActiveSnapshot(), InvalidSnapshot,
- None_Receiver, params,
- stmt->analyze);
+ None_Receiver, params, es->analyze);
INSTR_TIME_SET_CURRENT(starttime);
/* If analyzing, we need to cope with queued triggers */
- if (stmt->analyze)
+ if (es->analyze)
AfterTriggerBeginQuery();
/* Select execution options */
- if (stmt->analyze)
+ if (es->analyze)
eflags = 0; /* default run-to-completion flags */
else
eflags = EXEC_FLAG_EXPLAIN_ONLY;
@@ -257,7 +279,7 @@ ExplainOnePlan(PlannedStmt *plannedstmt, ExplainStmt *stmt,
ExecutorStart(queryDesc, eflags);
/* Execute the plan for statistics if asked for */
- if (stmt->analyze)
+ if (es->analyze)
{
/* run the plan */
ExecutorRun(queryDesc, ForwardScanDirection, 0L);
@@ -267,15 +289,14 @@ ExplainOnePlan(PlannedStmt *plannedstmt, ExplainStmt *stmt,
}
/* Create textual dump of plan tree */
- initStringInfo(&buf);
- ExplainPrintPlan(&buf, queryDesc, stmt->analyze, stmt->verbose);
+ ExplainPrintPlan(es, queryDesc);
/*
* If we ran the command, run any AFTER triggers it queued. (Note this
* will not include DEFERRED triggers; since those don't run until end of
* transaction, we can't measure them.) Include into total runtime.
*/
- if (stmt->analyze)
+ if (es->analyze)
{
INSTR_TIME_SET_CURRENT(starttime);
AfterTriggerEndQuery(queryDesc->estate);
@@ -283,7 +304,7 @@ ExplainOnePlan(PlannedStmt *plannedstmt, ExplainStmt *stmt,
}
/* Print info about runtime of triggers */
- if (stmt->analyze)
+ if (es->analyze)
{
ResultRelInfo *rInfo;
bool show_relname;
@@ -295,12 +316,12 @@ ExplainOnePlan(PlannedStmt *plannedstmt, ExplainStmt *stmt,
show_relname = (numrels > 1 || targrels != NIL);
rInfo = queryDesc->estate->es_result_relations;
for (nr = 0; nr < numrels; rInfo++, nr++)
- report_triggers(rInfo, show_relname, &buf);
+ report_triggers(rInfo, show_relname, es->str);
foreach(l, targrels)
{
rInfo = (ResultRelInfo *) lfirst(l);
- report_triggers(rInfo, show_relname, &buf);
+ report_triggers(rInfo, show_relname, es->str);
}
}
@@ -317,45 +338,34 @@ ExplainOnePlan(PlannedStmt *plannedstmt, ExplainStmt *stmt,
PopActiveSnapshot();
/* We need a CCI just in case query expanded to multiple plans */
- if (stmt->analyze)
+ if (es->analyze)
CommandCounterIncrement();
totaltime += elapsed_time(&starttime);
- if (stmt->analyze)
- appendStringInfo(&buf, "Total runtime: %.3f ms\n",
+ if (es->analyze)
+ appendStringInfo(es->str, "Total runtime: %.3f ms\n",
1000.0 * totaltime);
- do_text_output_multiline(tstate, buf.data);
-
- pfree(buf.data);
}
/*
* ExplainPrintPlan -
- * convert a QueryDesc's plan tree to text and append it to 'str'
+ * convert a QueryDesc's plan tree to text and append it to es->str
*
- * 'analyze' means to include runtime instrumentation results
- * 'verbose' means a verbose printout (currently, it shows targetlists)
+ * The caller should have set up the options fields of *es, as well as
+ * initializing the output buffer es->str. Other fields in *es are
+ * initialized here.
*
* NB: will not work on utility statements
*/
void
-ExplainPrintPlan(StringInfo str, QueryDesc *queryDesc,
- bool analyze, bool verbose)
+ExplainPrintPlan(ExplainState *es, QueryDesc *queryDesc)
{
- ExplainState es;
-
Assert(queryDesc->plannedstmt != NULL);
-
- memset(&es, 0, sizeof(es));
- es.str = str;
- es.printTList = verbose;
- es.printAnalyze = analyze;
- es.pstmt = queryDesc->plannedstmt;
- es.rtable = queryDesc->plannedstmt->rtable;
-
+ es->pstmt = queryDesc->plannedstmt;
+ es->rtable = queryDesc->plannedstmt->rtable;
ExplainNode(queryDesc->plannedstmt->planTree, queryDesc->planstate,
- NULL, 0, &es);
+ NULL, 0, es);
}
/*
@@ -692,9 +702,10 @@ ExplainNode(Plan *plan, PlanState *planstate,
break;
}
- appendStringInfo(es->str, " (cost=%.2f..%.2f rows=%.0f width=%d)",
- plan->startup_cost, plan->total_cost,
- plan->plan_rows, plan->plan_width);
+ if (es->costs)
+ appendStringInfo(es->str, " (cost=%.2f..%.2f rows=%.0f width=%d)",
+ plan->startup_cost, plan->total_cost,
+ plan->plan_rows, plan->plan_width);
/*
* We have to forcibly clean up the instrumentation state because we
@@ -714,12 +725,12 @@ ExplainNode(Plan *plan, PlanState *planstate,
planstate->instrument->ntuples / nloops,
planstate->instrument->nloops);
}
- else if (es->printAnalyze)
+ else if (es->analyze)
appendStringInfoString(es->str, " (never executed)");
appendStringInfoChar(es->str, '\n');
/* target list */
- if (es->printTList)
+ if (es->verbose)
show_plan_tlist(plan, indent, es);
/* quals, sort keys, etc */
@@ -1025,7 +1036,7 @@ static void
show_sort_info(SortState *sortstate, int indent, ExplainState *es)
{
Assert(IsA(sortstate, SortState));
- if (es->printAnalyze && sortstate->sort_Done &&
+ if (es->analyze && sortstate->sort_Done &&
sortstate->tuplesortstate != NULL)
{
char *sortinfo;
diff --git a/src/backend/commands/prepare.c b/src/backend/commands/prepare.c
index 0e948e4b72d..4ee66969147 100644
--- a/src/backend/commands/prepare.c
+++ b/src/backend/commands/prepare.c
@@ -10,7 +10,7 @@
* Copyright (c) 2002-2009, PostgreSQL Global Development Group
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/commands/prepare.c,v 1.97 2009/06/11 14:48:56 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/commands/prepare.c,v 1.98 2009/07/26 23:34:17 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -18,7 +18,6 @@
#include "access/xact.h"
#include "catalog/pg_type.h"
-#include "commands/explain.h"
#include "commands/prepare.h"
#include "miscadmin.h"
#include "nodes/nodeFuncs.h"
@@ -641,9 +640,8 @@ DropAllPreparedStatements(void)
* not the original PREPARE; we get the latter string from the plancache.
*/
void
-ExplainExecuteQuery(ExecuteStmt *execstmt, ExplainStmt *stmt,
- const char *queryString,
- ParamListInfo params, TupOutputState *tstate)
+ExplainExecuteQuery(ExecuteStmt *execstmt, ExplainState *es,
+ const char *queryString, ParamListInfo params)
{
PreparedStatement *entry;
const char *query_string;
@@ -707,20 +705,18 @@ ExplainExecuteQuery(ExecuteStmt *execstmt, ExplainStmt *stmt,
pstmt->intoClause = execstmt->into;
}
- ExplainOnePlan(pstmt, stmt, query_string,
- paramLI, tstate);
+ ExplainOnePlan(pstmt, es, query_string, paramLI);
}
else
{
- ExplainOneUtility((Node *) pstmt, stmt, query_string,
- params, tstate);
+ ExplainOneUtility((Node *) pstmt, es, query_string, params);
}
/* No need for CommandCounterIncrement, as ExplainOnePlan did it */
/* put a blank line between plans */
if (!is_last_query)
- do_text_output_oneline(tstate, "");
+ appendStringInfoChar(es->str, '\n');
}
if (estate)
diff --git a/src/backend/nodes/copyfuncs.c b/src/backend/nodes/copyfuncs.c
index 0111ac4a9d9..0752cbfc00e 100644
--- a/src/backend/nodes/copyfuncs.c
+++ b/src/backend/nodes/copyfuncs.c
@@ -15,7 +15,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/nodes/copyfuncs.c,v 1.434 2009/07/20 02:42:27 adunstan Exp $
+ * $PostgreSQL: pgsql/src/backend/nodes/copyfuncs.c,v 1.435 2009/07/26 23:34:17 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -2875,8 +2875,7 @@ _copyExplainStmt(ExplainStmt *from)
ExplainStmt *newnode = makeNode(ExplainStmt);
COPY_NODE_FIELD(query);
- COPY_SCALAR_FIELD(verbose);
- COPY_SCALAR_FIELD(analyze);
+ COPY_NODE_FIELD(options);
return newnode;
}
diff --git a/src/backend/nodes/equalfuncs.c b/src/backend/nodes/equalfuncs.c
index c2e3f643d3e..121fbd0d2ee 100644
--- a/src/backend/nodes/equalfuncs.c
+++ b/src/backend/nodes/equalfuncs.c
@@ -22,7 +22,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/nodes/equalfuncs.c,v 1.357 2009/07/20 02:42:27 adunstan Exp $
+ * $PostgreSQL: pgsql/src/backend/nodes/equalfuncs.c,v 1.358 2009/07/26 23:34:18 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -1467,8 +1467,7 @@ static bool
_equalExplainStmt(ExplainStmt *a, ExplainStmt *b)
{
COMPARE_NODE_FIELD(query);
- COMPARE_SCALAR_FIELD(verbose);
- COMPARE_SCALAR_FIELD(analyze);
+ COMPARE_NODE_FIELD(options);
return true;
}
diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y
index c88073d33dd..c44bbe75c3b 100644
--- a/src/backend/parser/gram.y
+++ b/src/backend/parser/gram.y
@@ -11,7 +11,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/parser/gram.y,v 2.672 2009/07/25 00:07:11 adunstan Exp $
+ * $PostgreSQL: pgsql/src/backend/parser/gram.y,v 2.673 2009/07/26 23:34:18 tgl Exp $
*
* HISTORY
* AUTHOR DATE MAJOR EVENT
@@ -321,7 +321,7 @@ static TypeName *TableFuncTypeName(List *columns);
%type <list> opt_interval interval_second
%type <node> overlay_placing substr_from substr_for
-%type <boolean> opt_instead opt_analyze
+%type <boolean> opt_instead
%type <boolean> index_opt_unique opt_verbose opt_full
%type <boolean> opt_freeze opt_default opt_recheck
%type <defelt> opt_binary opt_oids copy_delimiter
@@ -368,6 +368,10 @@ static TypeName *TableFuncTypeName(List *columns);
%type <node> generic_option_arg
%type <defelt> generic_option_elem alter_generic_option_elem
%type <list> generic_option_list alter_generic_option_list
+%type <str> explain_option_name
+%type <node> explain_option_arg
+%type <defelt> explain_option_elem
+%type <list> explain_option_list
%type <typnam> Typename SimpleTypename ConstTypename
GenericType Numeric opt_float
@@ -2710,13 +2714,13 @@ opt_by: BY {}
;
NumericOnly:
- FCONST { $$ = makeFloat($1); }
+ FCONST { $$ = makeFloat($1); }
| '-' FCONST
{
$$ = makeFloat($2);
doNegateFloat($$);
}
- | SignedIconst { $$ = makeInteger($1); };
+ | SignedIconst { $$ = makeInteger($1); }
;
/*****************************************************************************
@@ -6473,16 +6477,41 @@ opt_name_list:
*
* QUERY:
* EXPLAIN [ANALYZE] [VERBOSE] query
+ * EXPLAIN ( options ) query
*
*****************************************************************************/
-ExplainStmt: EXPLAIN opt_analyze opt_verbose ExplainableStmt
+ExplainStmt:
+ EXPLAIN ExplainableStmt
+ {
+ ExplainStmt *n = makeNode(ExplainStmt);
+ n->query = $2;
+ n->options = NIL;
+ $$ = (Node *) n;
+ }
+ | EXPLAIN analyze_keyword opt_verbose ExplainableStmt
{
ExplainStmt *n = makeNode(ExplainStmt);
- n->analyze = $2;
- n->verbose = $3;
n->query = $4;
- $$ = (Node *)n;
+ n->options = list_make1(makeDefElem("analyze", NULL));
+ if ($3)
+ n->options = lappend(n->options,
+ makeDefElem("verbose", NULL));
+ $$ = (Node *) n;
+ }
+ | EXPLAIN VERBOSE ExplainableStmt
+ {
+ ExplainStmt *n = makeNode(ExplainStmt);
+ n->query = $3;
+ n->options = list_make1(makeDefElem("verbose", NULL));
+ $$ = (Node *) n;
+ }
+ | EXPLAIN '(' explain_option_list ')' ExplainableStmt
+ {
+ ExplainStmt *n = makeNode(ExplainStmt);
+ n->query = $5;
+ n->options = $3;
+ $$ = (Node *) n;
}
;
@@ -6496,9 +6525,35 @@ ExplainableStmt:
| ExecuteStmt /* by default all are $$=$1 */
;
-opt_analyze:
- analyze_keyword { $$ = TRUE; }
- | /* EMPTY */ { $$ = FALSE; }
+explain_option_list:
+ explain_option_elem
+ {
+ $$ = list_make1($1);
+ }
+ | explain_option_list ',' explain_option_elem
+ {
+ $$ = lappend($1, $3);
+ }
+ ;
+
+explain_option_elem:
+ explain_option_name explain_option_arg
+ {
+ $$ = makeDefElem($1, $2);
+ }
+ ;
+
+explain_option_name:
+ ColId { $$ = $1; }
+ | analyze_keyword { $$ = "analyze"; }
+ | VERBOSE { $$ = "verbose"; }
+ ;
+
+explain_option_arg:
+ opt_boolean { $$ = (Node *) makeString($1); }
+ | ColId_or_Sconst { $$ = (Node *) makeString($1); }
+ | NumericOnly { $$ = (Node *) $1; }
+ | /* EMPTY */ { $$ = NULL; }
;
/*****************************************************************************
diff --git a/src/backend/tcop/utility.c b/src/backend/tcop/utility.c
index bda06a37362..e3677c51d61 100644
--- a/src/backend/tcop/utility.c
+++ b/src/backend/tcop/utility.c
@@ -10,7 +10,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/tcop/utility.c,v 1.310 2009/07/16 06:33:44 petere Exp $
+ * $PostgreSQL: pgsql/src/backend/tcop/utility.c,v 1.311 2009/07/26 23:34:18 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -2316,10 +2316,20 @@ GetCommandLogLevel(Node *parsetree)
case T_ExplainStmt:
{
ExplainStmt *stmt = (ExplainStmt *) parsetree;
+ bool analyze = false;
+ ListCell *lc;
/* Look through an EXPLAIN ANALYZE to the contained stmt */
- if (stmt->analyze)
+ foreach(lc, stmt->options)
+ {
+ DefElem *opt = (DefElem *) lfirst(lc);
+
+ if (strcmp(opt->defname, "analyze") == 0)
+ analyze = defGetBoolean(opt);
+ }
+ if (analyze)
return GetCommandLogLevel(stmt->query);
+
/* Plain EXPLAIN isn't so interesting */
lev = LOGSTMT_ALL;
}
diff --git a/src/include/commands/explain.h b/src/include/commands/explain.h
index e5c61a0dcb6..a5cc40367f8 100644
--- a/src/include/commands/explain.h
+++ b/src/include/commands/explain.h
@@ -6,7 +6,7 @@
* Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
* Portions Copyright (c) 1994-5, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/include/commands/explain.h,v 1.39 2009/06/11 14:49:11 momjian Exp $
+ * $PostgreSQL: pgsql/src/include/commands/explain.h,v 1.40 2009/07/26 23:34:18 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -15,12 +15,23 @@
#include "executor/executor.h"
+typedef struct ExplainState
+{
+ StringInfo str; /* output buffer */
+ /* options */
+ bool verbose; /* print plan targetlists */
+ bool analyze; /* print actual times */
+ bool costs; /* print costs */
+ /* other states */
+ PlannedStmt *pstmt; /* top of plan */
+ List *rtable; /* range table */
+} ExplainState;
+
/* Hook for plugins to get control in ExplainOneQuery() */
typedef void (*ExplainOneQuery_hook_type) (Query *query,
- ExplainStmt *stmt,
- const char *queryString,
- ParamListInfo params,
- TupOutputState *tstate);
+ ExplainState *es,
+ const char *queryString,
+ ParamListInfo params);
extern PGDLLIMPORT ExplainOneQuery_hook_type ExplainOneQuery_hook;
/* Hook for plugins to get control in explain_get_index_name() */
@@ -31,19 +42,16 @@ extern PGDLLIMPORT explain_get_index_name_hook_type explain_get_index_name_hook;
extern void ExplainQuery(ExplainStmt *stmt, const char *queryString,
ParamListInfo params, DestReceiver *dest);
+extern void ExplainInitState(ExplainState *es);
+
extern TupleDesc ExplainResultDesc(ExplainStmt *stmt);
-extern void ExplainOneUtility(Node *utilityStmt, ExplainStmt *stmt,
- const char *queryString,
- ParamListInfo params,
- TupOutputState *tstate);
+extern void ExplainOneUtility(Node *utilityStmt, ExplainState *es,
+ const char *queryString, ParamListInfo params);
-extern void ExplainOnePlan(PlannedStmt *plannedstmt, ExplainStmt *stmt,
- const char *queryString,
- ParamListInfo params,
- TupOutputState *tstate);
+extern void ExplainOnePlan(PlannedStmt *plannedstmt, ExplainState *es,
+ const char *queryString, ParamListInfo params);
-extern void ExplainPrintPlan(StringInfo str, QueryDesc *queryDesc,
- bool analyze, bool verbose);
+extern void ExplainPrintPlan(ExplainState *es, QueryDesc *queryDesc);
#endif /* EXPLAIN_H */
diff --git a/src/include/commands/prepare.h b/src/include/commands/prepare.h
index f52f0012895..4f9cb262275 100644
--- a/src/include/commands/prepare.h
+++ b/src/include/commands/prepare.h
@@ -6,14 +6,14 @@
*
* Copyright (c) 2002-2009, PostgreSQL Global Development Group
*
- * $PostgreSQL: pgsql/src/include/commands/prepare.h,v 1.30 2009/01/01 17:23:58 momjian Exp $
+ * $PostgreSQL: pgsql/src/include/commands/prepare.h,v 1.31 2009/07/26 23:34:18 tgl Exp $
*
*-------------------------------------------------------------------------
*/
#ifndef PREPARE_H
#define PREPARE_H
-#include "executor/executor.h"
+#include "commands/explain.h"
#include "utils/plancache.h"
#include "utils/timestamp.h"
@@ -40,9 +40,8 @@ extern void ExecuteQuery(ExecuteStmt *stmt, const char *queryString,
ParamListInfo params,
DestReceiver *dest, char *completionTag);
extern void DeallocateQuery(DeallocateStmt *stmt);
-extern void ExplainExecuteQuery(ExecuteStmt *execstmt, ExplainStmt *stmt,
- const char *queryString,
- ParamListInfo params, TupOutputState *tstate);
+extern void ExplainExecuteQuery(ExecuteStmt *execstmt, ExplainState *es,
+ const char *queryString, ParamListInfo params);
/* Low-level access to stored prepared statements */
extern void StorePreparedStatement(const char *stmt_name,
diff --git a/src/include/nodes/parsenodes.h b/src/include/nodes/parsenodes.h
index b54b170425c..5947c6acc98 100644
--- a/src/include/nodes/parsenodes.h
+++ b/src/include/nodes/parsenodes.h
@@ -13,7 +13,7 @@
* Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/include/nodes/parsenodes.h,v 1.397 2009/07/20 02:42:28 adunstan Exp $
+ * $PostgreSQL: pgsql/src/include/nodes/parsenodes.h,v 1.398 2009/07/26 23:34:18 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -2193,8 +2193,7 @@ typedef struct ExplainStmt
{
NodeTag type;
Node *query; /* the query (as a raw parse tree) */
- bool verbose; /* print plan info */
- bool analyze; /* get statistics by executing plan */
+ List *options; /* list of DefElem nodes */
} ExplainStmt;
/* ----------------------