From 888c458950fffe267e2f3a953cb29a9361a0411e Mon Sep 17 00:00:00 2001 From: Radu Berinde Date: Wed, 15 Jul 2020 11:16:06 -0700 Subject: [PATCH] sql: be more strict with validating EXPLAIN Verify during paring that we are not specifying an invalid mode for `EXPLAIN ANALYZE`. Fixes #51473. Release note: None --- pkg/sql/parser/parse_test.go | 43 ++++++++++++++++++++++++++++++++++++ pkg/sql/sem/tree/explain.go | 17 +++++++++++--- pkg/sql/sem/tree/pretty.go | 4 +++- 3 files changed, 60 insertions(+), 4 deletions(-) diff --git a/pkg/sql/parser/parse_test.go b/pkg/sql/parser/parse_test.go index aaa71853a8be..6a6ba6951602 100644 --- a/pkg/sql/parser/parse_test.go +++ b/pkg/sql/parser/parse_test.go @@ -2817,6 +2817,49 @@ EXPLAIN EXECUTE a ^ HINT: try \h EXPLAIN`, }, + { + `EXPLAIN ANALYZE (PLAN) SELECT 1`, + `at or near "EOF": syntax error: EXPLAIN ANALYZE cannot be used with PLAN +DETAIL: source SQL: +EXPLAIN ANALYZE (PLAN) SELECT 1 + ^`, + }, + { + `EXPLAIN (ANALYZE, PLAN) SELECT 1`, + `at or near "analyze": syntax error +DETAIL: source SQL: +EXPLAIN (ANALYZE, PLAN) SELECT 1 + ^ +HINT: try \h `, + }, + { + `EXPLAIN ANALYZE (OPT) SELECT 1`, + `at or near "EOF": syntax error: EXPLAIN ANALYZE cannot be used with OPT +DETAIL: source SQL: +EXPLAIN ANALYZE (OPT) SELECT 1 + ^`, + }, + { + `EXPLAIN ANALYZE (VEC) SELECT 1`, + `at or near "EOF": syntax error: EXPLAIN ANALYZE cannot be used with VEC +DETAIL: source SQL: +EXPLAIN ANALYZE (VEC) SELECT 1 + ^`, + }, + { + `EXPLAIN (DEBUG) SELECT 1`, + `at or near "EOF": syntax error: DEBUG flag can only be used with EXPLAIN ANALYZE +DETAIL: source SQL: +EXPLAIN (DEBUG) SELECT 1 + ^`, + }, + { + `EXPLAIN (PLAN, DEBUG) SELECT 1`, + `at or near "EOF": syntax error: DEBUG flag can only be used with EXPLAIN ANALYZE +DETAIL: source SQL: +EXPLAIN (PLAN, DEBUG) SELECT 1 + ^`, + }, { `SELECT $0`, `lexical error: placeholder index must be between 1 and 65536 diff --git a/pkg/sql/sem/tree/explain.go b/pkg/sql/sem/tree/explain.go index b4e2904dadb0..8592439efa3c 100644 --- a/pkg/sql/sem/tree/explain.go +++ b/pkg/sql/sem/tree/explain.go @@ -124,13 +124,15 @@ func (f ExplainFlag) String() string { // Format implements the NodeFormatter interface. func (node *Explain) Format(ctx *FmtCtx) { ctx.WriteString("EXPLAIN ") + showMode := node.Mode != ExplainPlan // ANALYZE is a special case because it is a statement implemented as an // option to EXPLAIN. if node.Flags[ExplainFlagAnalyze] { ctx.WriteString("ANALYZE ") + showMode = true } wroteFlag := false - if node.Mode != ExplainPlan { + if showMode { fmt.Fprintf(ctx, "(%s", node.Mode) wroteFlag = true } @@ -207,10 +209,19 @@ func MakeExplain(options []string, stmt Statement) (Statement, error) { } opts.Flags[flag] = true } + analyze := opts.Flags[ExplainFlagAnalyze] if opts.Mode == 0 { - // Default mode is ExplainPlan. - opts.Mode = ExplainPlan + if analyze { + // ANALYZE implies DISTSQL. + opts.Mode = ExplainDistSQL + } else { + // Default mode is ExplainPlan. + opts.Mode = ExplainPlan + } + } else if analyze && opts.Mode != ExplainDistSQL { + return nil, pgerror.Newf(pgcode.Syntax, "EXPLAIN ANALYZE cannot be used with %s", opts.Mode) } + return &Explain{ ExplainOptions: opts, Statement: stmt, diff --git a/pkg/sql/sem/tree/pretty.go b/pkg/sql/sem/tree/pretty.go index ad25652ff67a..096dcc202e8c 100644 --- a/pkg/sql/sem/tree/pretty.go +++ b/pkg/sql/sem/tree/pretty.go @@ -2017,13 +2017,15 @@ func (node *Export) doc(p *PrettyCfg) pretty.Doc { func (node *Explain) doc(p *PrettyCfg) pretty.Doc { d := pretty.Keyword("EXPLAIN") + showMode := node.Mode != ExplainPlan // ANALYZE is a special case because it is a statement implemented as an // option to EXPLAIN. if node.Flags[ExplainFlagAnalyze] { d = pretty.ConcatSpace(d, pretty.Keyword("ANALYZE")) + showMode = true } var opts []pretty.Doc - if node.Mode != ExplainPlan { + if showMode { opts = append(opts, pretty.Keyword(node.Mode.String())) } for f := ExplainFlag(1); f <= numExplainFlags; f++ {