*** a/contrib/auto_explain/auto_explain.c
--- b/contrib/auto_explain/auto_explain.c
***************
*** 14,19 ****
--- 14,20 ----
#include "commands/explain.h"
#include "executor/instrument.h"
+ #include "nodes/makefuncs.h"
#include "utils/guc.h"
PG_MODULE_MAGIC;
***************
*** 196,207 **** explain_ExecutorEnd(QueryDesc *queryDesc)
msec = queryDesc->totaltime->total * 1000.0;
if (msec >= auto_explain_log_min_duration)
{
StringInfoData buf;
initStringInfo(&buf);
! ExplainPrintPlan(&buf, queryDesc,
! queryDesc->doInstrument && auto_explain_log_analyze,
! auto_explain_log_verbose);
/* Remove last line break */
if (buf.len > 0 && buf.data[buf.len - 1] == '\n')
--- 197,210 ----
msec = queryDesc->totaltime->total * 1000.0;
if (msec >= auto_explain_log_min_duration)
{
+ ExplainStmt *stmt = makeExplain(NIL, NULL);
StringInfoData buf;
initStringInfo(&buf);
! stmt->analyze =
! (queryDesc->doInstrument && auto_explain_log_analyze);
! stmt->verbose = auto_explain_log_verbose;
! ExplainPrintPlan(&buf, queryDesc, stmt);
/* Remove last line break */
if (buf.len > 0 && buf.data[buf.len - 1] == '\n')
*** a/doc/src/sgml/ref/explain.sgml
--- b/doc/src/sgml/ref/explain.sgml
***************
*** 31,36 **** PostgreSQL documentation
--- 31,37 ----
+ EXPLAIN [ ( [ { ANALYZE | VERBOSE | COSTS } [ boolean_value ] ] [, ...] ) ] statement
EXPLAIN [ ANALYZE ] [ VERBOSE ] statement
***************
*** 70,75 **** EXPLAIN [ ANALYZE ] [ VERBOSE ] statement
+
+ Only the ANALYZE and VERBOSE options
+ can be specified, and only in the order, without surrounding the option list
+ in parentheses. Prior to PostgreSQL 8.5, the
+ unparenthesized syntax was the only one supported. It is expected that
+ all new options will be supported only when using the parenthesized syntax,
+ which also allows a value to be specified for each option
+ (e.g. TRUE or FALSE).
+
+
Keep in mind that the statement is actually executed when
***************
*** 99,105 **** ROLLBACK;
ANALYZE
! Carry out the command and show the actual run times.
--- 110,117 ----
ANALYZE
! Carry out the command and show the actual run times. This
! parameter defaults to FALSE.
***************
*** 108,114 **** ROLLBACK;
VERBOSE
! Include the output column list for each node in the plan tree.
--- 120,151 ----
VERBOSE
! Include the output column list for each node in the plan tree. This
! parameter defaults to FALSE.
!
!
!
!
!
! COSTS
!
!
! Include information on the estimated startup and total cost of each
! plan node, as well as the estimated number of rows and the estimated
! width of each row. This parameter defaults to TRUE.
!
!
!
!
!
! boolean_value
!
!
! Specifies whether the named parameter should be turned on or off. You
! can use the values TRUE or 1 to
! request the stated option, and FALSE
! or 0. If the Boolean value is omitted, it defaults
! to TRUE.
***************
*** 202,207 **** EXPLAIN SELECT * FROM foo WHERE i = 4;
--- 239,258 ----
+ Here is the same plan with costs suppressed:
+
+
+ EXPLAIN (COSTS FALSE) SELECT * FROM foo WHERE i = 4;
+
+ QUERY PLAN
+ ----------------------------
+ Index Scan using fi on foo
+ Index Cond: (i = 4)
+ (2 rows)
+
+
+
+
Here is an example of a query plan for a query using an aggregate
function:
*** a/src/backend/commands/explain.c
--- b/src/backend/commands/explain.c
***************
*** 46,51 **** typedef struct ExplainState
--- 46,52 ----
/* options */
bool printTList; /* print plan targetlists */
bool printAnalyze; /* print actual times */
+ bool printCosts; /* print costs */
/* other states */
PlannedStmt *pstmt; /* top of plan */
List *rtable; /* range table */
***************
*** 268,274 **** ExplainOnePlan(PlannedStmt *plannedstmt, ExplainStmt *stmt,
/* Create textual dump of plan tree */
initStringInfo(&buf);
! ExplainPrintPlan(&buf, queryDesc, stmt->analyze, stmt->verbose);
/*
* If we ran the command, run any AFTER triggers it queued. (Note this
--- 269,275 ----
/* Create textual dump of plan tree */
initStringInfo(&buf);
! ExplainPrintPlan(&buf, queryDesc, stmt);
/*
* If we ran the command, run any AFTER triggers it queued. (Note this
***************
*** 340,347 **** ExplainOnePlan(PlannedStmt *plannedstmt, ExplainStmt *stmt,
* NB: will not work on utility statements
*/
void
! ExplainPrintPlan(StringInfo str, QueryDesc *queryDesc,
! bool analyze, bool verbose)
{
ExplainState es;
--- 341,347 ----
* NB: will not work on utility statements
*/
void
! ExplainPrintPlan(StringInfo str, QueryDesc *queryDesc, ExplainStmt *stmt)
{
ExplainState es;
***************
*** 349,356 **** ExplainPrintPlan(StringInfo str, QueryDesc *queryDesc,
memset(&es, 0, sizeof(es));
es.str = str;
! es.printTList = verbose;
! es.printAnalyze = analyze;
es.pstmt = queryDesc->plannedstmt;
es.rtable = queryDesc->plannedstmt->rtable;
--- 349,357 ----
memset(&es, 0, sizeof(es));
es.str = str;
! es.printTList = stmt->verbose;
! es.printAnalyze = stmt->analyze;
! es.printCosts = stmt->costs;
es.pstmt = queryDesc->plannedstmt;
es.rtable = queryDesc->plannedstmt->rtable;
***************
*** 688,696 **** ExplainNode(Plan *plan, PlanState *planstate, Plan *outer_plan,
break;
}
! 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
--- 689,698 ----
break;
}
! if (es->printCosts)
! 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
*** a/src/backend/nodes/copyfuncs.c
--- b/src/backend/nodes/copyfuncs.c
***************
*** 2877,2882 **** _copyExplainStmt(ExplainStmt *from)
--- 2877,2883 ----
COPY_NODE_FIELD(query);
COPY_SCALAR_FIELD(verbose);
COPY_SCALAR_FIELD(analyze);
+ COPY_SCALAR_FIELD(costs);
return newnode;
}
*** a/src/backend/nodes/equalfuncs.c
--- b/src/backend/nodes/equalfuncs.c
***************
*** 1469,1474 **** _equalExplainStmt(ExplainStmt *a, ExplainStmt *b)
--- 1469,1475 ----
COMPARE_NODE_FIELD(query);
COMPARE_SCALAR_FIELD(verbose);
COMPARE_SCALAR_FIELD(analyze);
+ COMPARE_SCALAR_FIELD(costs);
return true;
}
*** a/src/backend/nodes/makefuncs.c
--- b/src/backend/nodes/makefuncs.c
***************
*** 17,25 ****
#include "catalog/pg_type.h"
#include "nodes/makefuncs.h"
#include "utils/lsyscache.h"
-
/*
* makeA_Expr -
* makes an A_Expr node
--- 17,25 ----
#include "catalog/pg_type.h"
#include "nodes/makefuncs.h"
+ #include "utils/builtins.h"
#include "utils/lsyscache.h"
/*
* makeA_Expr -
* makes an A_Expr node
***************
*** 385,387 **** makeDefElemExtended(char *nameSpace, char *name, Node *arg,
--- 385,418 ----
return res;
}
+
+ /*
+ * makeExplain -
+ * build an ExplainStmt node by parsing the generic options list
+ */
+ ExplainStmt *
+ makeExplain(List *options, Node *query)
+ {
+ ExplainStmt *n = makeNode(ExplainStmt);
+ ListCell *lc;
+
+ n->costs = true;
+ n->query = query;
+
+ foreach (lc, options)
+ {
+ DefElem *opt = lfirst(lc);
+ if (!strcmp(opt->defname, "analyze"))
+ n->analyze = defGetBoolean(opt);
+ else if (!strcmp(opt->defname, "verbose"))
+ n->verbose = defGetBoolean(opt);
+ else if (!strcmp(opt->defname, "costs"))
+ n->costs = defGetBoolean(opt);
+ else
+ ereport(ERROR,
+ (errcode(ERRCODE_UNDEFINED_PARAMETER),
+ errmsg("unknown EXPLAIN option: %s", opt->defname)));
+ }
+
+ return n;
+ }
*** a/src/backend/parser/gram.y
--- b/src/backend/parser/gram.y
***************
*** 321,327 **** static TypeName *TableFuncTypeName(List *columns);
%type opt_interval interval_second
%type overlay_placing substr_from substr_for
! %type opt_instead opt_analyze
%type index_opt_unique opt_verbose opt_full
%type opt_freeze opt_default opt_recheck
%type opt_binary opt_oids copy_delimiter
--- 321,327 ----
%type opt_interval interval_second
%type overlay_placing substr_from substr_for
! %type opt_instead
%type index_opt_unique opt_verbose opt_full
%type opt_freeze opt_default opt_recheck
%type opt_binary opt_oids copy_delimiter
***************
*** 369,374 **** static TypeName *TableFuncTypeName(List *columns);
--- 369,379 ----
%type generic_option_elem alter_generic_option_elem
%type generic_option_list alter_generic_option_list
+ %type explain_option_name
+ %type explain_option_arg
+ %type explain_option_elem
+ %type explain_option_list
+
%type Typename SimpleTypename ConstTypename
GenericType Numeric opt_float
Character ConstCharacter
***************
*** 6469,6485 **** opt_name_list:
*
* QUERY:
* EXPLAIN [ANALYZE] [VERBOSE] query
*
*****************************************************************************/
! ExplainStmt: EXPLAIN opt_analyze opt_verbose ExplainableStmt
{
! ExplainStmt *n = makeNode(ExplainStmt);
! n->analyze = $2;
n->verbose = $3;
- n->query = $4;
$$ = (Node *)n;
}
;
ExplainableStmt:
--- 6474,6506 ----
*
* QUERY:
* EXPLAIN [ANALYZE] [VERBOSE] query
+ * EXPLAIN ( options ) query
*
*****************************************************************************/
! ExplainStmt:
! EXPLAIN ExplainableStmt
! {
! ExplainStmt *n = makeExplain(NIL, (Node *) $2);
! $$ = (Node *)n;
! }
! | EXPLAIN ANALYZE opt_verbose ExplainableStmt
{
! ExplainStmt *n = makeExplain(NIL, (Node *) $4);
! n->analyze = TRUE;
n->verbose = $3;
$$ = (Node *)n;
}
+ | EXPLAIN VERBOSE ExplainableStmt
+ {
+ ExplainStmt *n = makeExplain(NIL, (Node *) $3);
+ n->verbose = TRUE;
+ $$ = (Node *)n;
+ }
+ | EXPLAIN '(' explain_option_list ')' ExplainableStmt
+ {
+ $$ = (Node *) makeExplain((List *) $3, (Node *) $5);
+ }
;
ExplainableStmt:
***************
*** 6492,6500 **** ExplainableStmt:
| ExecuteStmt /* by default all are $$=$1 */
;
! opt_analyze:
! analyze_keyword { $$ = TRUE; }
! | /* EMPTY */ { $$ = FALSE; }
;
/*****************************************************************************
--- 6513,6547 ----
| ExecuteStmt /* by default all are $$=$1 */
;
! 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; }
! | VERBOSE { $$ = "verbose"; }
! | analyze_keyword { $$ = "analyze"; }
! ;
!
! explain_option_arg:
! opt_boolean { $$ = (Node *) makeString($1); }
! | ColId_or_Sconst { $$ = (Node *) makeString($1); }
! | SignedIconst { $$ = (Node *) makeInteger($1); }
! | /* EMPTY */ { $$ = NULL; }
;
/*****************************************************************************
*** a/src/include/commands/explain.h
--- b/src/include/commands/explain.h
***************
*** 44,49 **** extern void ExplainOnePlan(PlannedStmt *plannedstmt, ExplainStmt *stmt,
TupOutputState *tstate);
extern void ExplainPrintPlan(StringInfo str, QueryDesc *queryDesc,
! bool analyze, bool verbose);
#endif /* EXPLAIN_H */
--- 44,49 ----
TupOutputState *tstate);
extern void ExplainPrintPlan(StringInfo str, QueryDesc *queryDesc,
! ExplainStmt *stmt);
#endif /* EXPLAIN_H */
*** a/src/include/nodes/makefuncs.h
--- b/src/include/nodes/makefuncs.h
***************
*** 69,72 **** extern DefElem *makeDefElem(char *name, Node *arg);
--- 69,74 ----
extern DefElem *makeDefElemExtended(char *nameSpace, char *name, Node *arg,
DefElemAction defaction);
+ extern ExplainStmt *makeExplain(List *options, Node *query);
+
#endif /* MAKEFUNC_H */
*** a/src/include/nodes/parsenodes.h
--- b/src/include/nodes/parsenodes.h
***************
*** 2194,2200 **** 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 */
} ExplainStmt;
/* ----------------------
--- 2194,2201 ----
NodeTag type;
Node *query; /* the query (as a raw parse tree) */
bool verbose; /* print plan info */
! bool analyze; /* actually execute plan */
! bool costs; /* print costs and times */
} ExplainStmt;
/* ----------------------