github.com/cockroachdb/cockroach@v20.2.0-alpha.1+incompatible/pkg/sql/sem/tree/explain.go (about) 1 // Copyright 2015 The Cockroach Authors. 2 // 3 // Use of this software is governed by the Business Source License 4 // included in the file licenses/BSL.txt. 5 // 6 // As of the Change Date specified in that file, in accordance with 7 // the Business Source License, use of this software will be governed 8 // by the Apache License, Version 2.0, included in the file 9 // licenses/APL.txt. 10 11 package tree 12 13 import ( 14 "fmt" 15 "strings" 16 17 "github.com/cockroachdb/cockroach/pkg/sql/pgwire/pgcode" 18 "github.com/cockroachdb/cockroach/pkg/sql/pgwire/pgerror" 19 "github.com/cockroachdb/errors" 20 ) 21 22 // Explain represents an EXPLAIN statement. 23 type Explain struct { 24 ExplainOptions 25 26 // Statement is the statement being EXPLAINed. 27 Statement Statement 28 } 29 30 // ExplainOptions contains information about the options passed to an EXPLAIN 31 // statement. 32 type ExplainOptions struct { 33 Mode ExplainMode 34 Flags [numExplainFlags + 1]bool 35 } 36 37 // ExplainMode indicates the mode of the explain. Currently there are two modes: 38 // PLAN (the default) and DISTSQL. 39 type ExplainMode uint8 40 41 const ( 42 // ExplainPlan shows information about the planNode tree for a query. 43 ExplainPlan ExplainMode = 1 + iota 44 45 // ExplainDistSQL shows the physical distsql plan for a query and whether a 46 // query would be run in "auto" DISTSQL mode. See sql/explain_distsql.go for 47 // details. If the ANALYZE option is included, the plan is also executed and 48 // execution statistics are collected and shown in the diagram. 49 ExplainDistSQL 50 51 // ExplainOpt shows the optimized relational expression (from the cost-based 52 // optimizer). 53 ExplainOpt 54 55 // ExplainVec shows the physical vectorized plan for a query and whether a 56 // query would be run in "auto" vectorized mode. 57 ExplainVec 58 59 numExplainModes = iota 60 ) 61 62 var explainModeStrings = [...]string{ 63 ExplainPlan: "PLAN", 64 ExplainDistSQL: "DISTSQL", 65 ExplainOpt: "OPT", 66 ExplainVec: "VEC", 67 } 68 69 var explainModeStringMap = func() map[string]ExplainMode { 70 m := make(map[string]ExplainMode, numExplainModes) 71 for i := ExplainMode(1); i <= numExplainModes; i++ { 72 m[explainModeStrings[i]] = i 73 } 74 return m 75 }() 76 77 func (m ExplainMode) String() string { 78 if m == 0 || m > numExplainModes { 79 panic(errors.AssertionFailedf("invalid ExplainMode %d", m)) 80 } 81 return explainModeStrings[m] 82 } 83 84 // ExplainFlag is a modifier in an EXPLAIN statement (like VERBOSE). 85 type ExplainFlag uint8 86 87 // Explain flags. 88 const ( 89 ExplainFlagVerbose ExplainFlag = 1 + iota 90 ExplainFlagSymVars 91 ExplainFlagTypes 92 ExplainFlagNoNormalize 93 ExplainFlagAnalyze 94 ExplainFlagEnv 95 ExplainFlagCatalog 96 numExplainFlags = iota 97 ) 98 99 var explainFlagStrings = [...]string{ 100 ExplainFlagVerbose: "VERBOSE", 101 ExplainFlagSymVars: "SYMVARS", 102 ExplainFlagTypes: "TYPES", 103 ExplainFlagNoNormalize: "NONORMALIZE", 104 ExplainFlagAnalyze: "ANALYZE", 105 ExplainFlagEnv: "ENV", 106 ExplainFlagCatalog: "CATALOG", 107 } 108 109 var explainFlagStringMap = func() map[string]ExplainFlag { 110 m := make(map[string]ExplainFlag, numExplainFlags) 111 for i := ExplainFlag(1); i <= numExplainFlags; i++ { 112 m[explainFlagStrings[i]] = i 113 } 114 return m 115 }() 116 117 func (f ExplainFlag) String() string { 118 if f == 0 || f > numExplainFlags { 119 panic(errors.AssertionFailedf("invalid ExplainFlag %d", f)) 120 } 121 return explainFlagStrings[f] 122 } 123 124 // Format implements the NodeFormatter interface. 125 func (node *Explain) Format(ctx *FmtCtx) { 126 ctx.WriteString("EXPLAIN ") 127 // ANALYZE is a special case because it is a statement implemented as an 128 // option to EXPLAIN. 129 if node.Flags[ExplainFlagAnalyze] { 130 ctx.WriteString("ANALYZE ") 131 } 132 wroteFlag := false 133 if node.Mode != ExplainPlan { 134 fmt.Fprintf(ctx, "(%s", node.Mode) 135 wroteFlag = true 136 } 137 138 for f := ExplainFlag(1); f <= numExplainFlags; f++ { 139 if f != ExplainFlagAnalyze && node.Flags[f] { 140 if !wroteFlag { 141 ctx.WriteString("(") 142 wroteFlag = true 143 } else { 144 ctx.WriteString(", ") 145 } 146 ctx.WriteString(f.String()) 147 } 148 } 149 if wroteFlag { 150 ctx.WriteString(") ") 151 } 152 ctx.FormatNode(node.Statement) 153 } 154 155 // ExplainAnalyzeDebug represents an EXPLAIN ANALYZE (DEBUG) statement. It is a 156 // different node type than Explain to allow easier special treatment in the SQL 157 // layer. 158 type ExplainAnalyzeDebug struct { 159 Statement Statement 160 } 161 162 // Format implements the NodeFormatter interface. 163 func (node *ExplainAnalyzeDebug) Format(ctx *FmtCtx) { 164 ctx.WriteString("EXPLAIN ANALYZE (DEBUG) ") 165 ctx.FormatNode(node.Statement) 166 } 167 168 // MakeExplain parses the EXPLAIN option strings and generates an explain 169 // statement. 170 func MakeExplain(options []string, stmt Statement) (Statement, error) { 171 for i := range options { 172 options[i] = strings.ToUpper(options[i]) 173 } 174 find := func(o string) bool { 175 for i := range options { 176 if options[i] == o { 177 return true 178 } 179 } 180 return false 181 } 182 183 if find("DEBUG") { 184 if !find("ANALYZE") { 185 return nil, pgerror.Newf(pgcode.Syntax, "DEBUG flag can only be used with EXPLAIN ANALYZE") 186 } 187 if len(options) != 2 { 188 return nil, pgerror.Newf( 189 pgcode.Syntax, "EXPLAIN ANALYZE (DEBUG) cannot be used in conjunction with other flags") 190 } 191 return &ExplainAnalyzeDebug{Statement: stmt}, nil 192 } 193 194 var opts ExplainOptions 195 for _, opt := range options { 196 opt = strings.ToUpper(opt) 197 if m, ok := explainModeStringMap[opt]; ok { 198 if opts.Mode != 0 { 199 return nil, pgerror.Newf(pgcode.Syntax, "cannot set EXPLAIN mode more than once: %s", opt) 200 } 201 opts.Mode = m 202 continue 203 } 204 flag, ok := explainFlagStringMap[opt] 205 if !ok { 206 return nil, pgerror.Newf(pgcode.Syntax, "unsupported EXPLAIN option: %s", opt) 207 } 208 opts.Flags[flag] = true 209 } 210 if opts.Mode == 0 { 211 // Default mode is ExplainPlan. 212 opts.Mode = ExplainPlan 213 } 214 return &Explain{ 215 ExplainOptions: opts, 216 Statement: stmt, 217 }, nil 218 }