Here's an updated version of my "generic options for explain" patch.
http://archives.postgresql.org/message-id/603c8f070905231747j2e099c23hef8eafbf26682...@mail.gmail.com This is rebased to CVS HEAD, post pgindent. Also, I've made a few changes to the syntax. Previously, I suggested this syntax: explain (analyze 'on', verbose 'off') query... Greg Stark suggested that for boolean parameters we might allow the argument to be omitted and default to true. http://archives.postgresql.org/message-id/4c72394c-384f-4fc4-be3e-8f556fbd3...@enterprisedb.com That seemed like a good idea so I did it. I also took it a step further and did something we've done elsewhere in the parser so that in many cases the quotes aren't even necessary. Thus you can now also write: explain (analyze on, verbose off) query... Of course, we don't have any consensus on the right syntax, but my previous proposal had at least as much support as any of the other alternatives that were offered, so we'll see where we get with this one. Followup patch that adds actual new functionality coming shortly. ...Robert
*** a/src/backend/nodes/makefuncs.c --- b/src/backend/nodes/makefuncs.c *************** *** 17,24 **** --- 17,26 ---- #include "catalog/pg_type.h" #include "nodes/makefuncs.h" + #include "utils/builtins.h" #include "utils/lsyscache.h" + static bool parseBooleanOption(DefElem *opt); /* * makeA_Expr - *************** *** 385,387 **** makeDefElemExtended(char *namespace, char *name, Node *arg, --- 387,453 ---- 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; + + foreach (lc, options) + { + DefElem *opt = lfirst(lc); + if (!strcmp(opt->defname, "analyze")) + n->analyze = parseBooleanOption(opt); + else if (!strcmp(opt->defname, "verbose")) + n->verbose = parseBooleanOption(opt); + else + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_PARAMETER), + errmsg("unknown EXPLAIN option: %s", opt->defname))); + } + + n->query = query; + return n; + } + + /* + * parseBooleanOption - + * Interpret a DefElem option as a boolean. + */ + static bool + parseBooleanOption(DefElem *opt) + { + bool res; + + /* + * We interpret an omitted boolean argument as equivalent to "true", so + * that, for example, EXPLAIN (ANALYZE) means the same thing as + * EXPLAIN (ANALYZE ON). + */ + if (!opt->arg) + { + return true; + } + else if (IsA(opt->arg, Integer)) + { + if (intVal(opt->arg) == 0) + return false; + else if (intVal(opt->arg) == 1) + return true; + } + else if (IsA(opt->arg, String)) + { + if (parse_bool(strVal(opt->arg), &res)) + return res; + } + + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("parameter \"%s\" requires a Boolean value", + opt->defname))); + } *** a/src/backend/parser/gram.y --- b/src/backend/parser/gram.y *************** *** 366,371 **** static TypeName *TableFuncTypeName(List *columns); --- 366,376 ---- %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 Character ConstCharacter *************** *** 6441,6457 **** 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: --- 6446,6466 ---- * * QUERY: * EXPLAIN [ANALYZE] [VERBOSE] query + * EXPLAIN ( options ) query * *****************************************************************************/ ExplainStmt: EXPLAIN opt_analyze opt_verbose ExplainableStmt { ! ExplainStmt *n = makeExplain(NIL, (Node *) $4); n->analyze = $2; n->verbose = $3; $$ = (Node *)n; } + | EXPLAIN '(' explain_option_list ')' ExplainableStmt + { + $$ = (Node *) makeExplain((List *) $3, (Node *) $5); + } ; ExplainableStmt: *************** *** 6464,6472 **** ExplainableStmt: | ExecuteStmt /* by default all are $$=$1 */ ; opt_analyze: analyze_keyword { $$ = TRUE; } ! | /* EMPTY */ { $$ = FALSE; } ; /***************************************************************************** --- 6473,6523 ---- | ExecuteStmt /* by default all are $$=$1 */ ; + /* + * The precedence declaration for the opt_analyze EMPTY case, below, is + * necessary to prevent a shift/reduce conflict in the second production for + * ExplainStmt, above. Otherwise, when the parser encounters "EXPLAIN (", it + * can't tell whether the "(" is the beginning of a SelectStmt or the beginning + * of the options list. The precedence declaration below forces the latter + * interpretation. + * + * It might seem that we could get away with simply changing the definition of + * ExplainableStmt to use select_without_parens rather than SelectStmt, but + * that does not work, because select_without_parens produces expressions such + * as "(SELECT NULL) ORDER BY 1" that we interpret as legal queries. + */ opt_analyze: analyze_keyword { $$ = TRUE; } ! | /* EMPTY */ %prec UMINUS { $$ = 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: ! ColLabel { $$ = $1; } ! ; ! ! explain_option_arg: ! opt_boolean { $$ = (Node *) makeString($1); } ! | ColId_or_Sconst { $$ = (Node *) makeString($1); } ! | SignedIconst { $$ = (Node *) makeInteger($1); } ! | /* EMPTY */ { $$ = NULL; } ; /***************************************************************************** *** 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 */
-- Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org) To make changes to your subscription: http://www.postgresql.org/mailpref/pgsql-hackers