github.com/matrixorigin/matrixone@v0.7.0/pkg/sql/plan/explain/explain_node.go (about) 1 // Copyright 2021 - 2022 Matrix Origin 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package explain 16 17 import ( 18 "context" 19 "strconv" 20 21 "github.com/matrixorigin/matrixone/pkg/common/moerr" 22 "github.com/matrixorigin/matrixone/pkg/pb/plan" 23 ) 24 25 var _ NodeDescribe = &NodeDescribeImpl{} 26 27 type NodeDescribeImpl struct { 28 Node *plan.Node 29 } 30 31 func NewNodeDescriptionImpl(node *plan.Node) *NodeDescribeImpl { 32 return &NodeDescribeImpl{ 33 Node: node, 34 } 35 } 36 37 const TableScan = "Table Scan" 38 const ExternalScan = "External Scan" 39 40 func (ndesc *NodeDescribeImpl) GetNodeBasicInfo(ctx context.Context, options *ExplainOptions) (string, error) { 41 var result string 42 var pname string /* node type name for text output */ 43 44 // Get the Node Name 45 switch ndesc.Node.NodeType { 46 case plan.Node_UNKNOWN: 47 pname = "UnKnow Node" 48 case plan.Node_VALUE_SCAN: 49 pname = "Values Scan" 50 case plan.Node_TABLE_SCAN: 51 pname = TableScan 52 case plan.Node_EXTERNAL_SCAN: 53 pname = ExternalScan 54 case plan.Node_MATERIAL_SCAN: 55 pname = "Material Scan" 56 case plan.Node_PROJECT: 57 pname = "Project" 58 case plan.Node_EXTERNAL_FUNCTION: 59 pname = "External Function" 60 case plan.Node_MATERIAL: 61 pname = "Material" 62 case plan.Node_RECURSIVE_CTE: 63 pname = "Recursive CTE" 64 case plan.Node_SINK: 65 pname = "Sink" 66 case plan.Node_SINK_SCAN: 67 pname = "Sink Scan" 68 case plan.Node_AGG: 69 pname = "Aggregate" 70 case plan.Node_DISTINCT: 71 pname = "Distinct" 72 case plan.Node_FILTER: 73 pname = "Filter" 74 case plan.Node_JOIN: 75 pname = "Join" 76 case plan.Node_SAMPLE: 77 pname = "Sample" 78 case plan.Node_SORT: 79 pname = "Sort" 80 case plan.Node_UNION: 81 pname = "Union" 82 case plan.Node_UNION_ALL: 83 pname = "Union All" 84 case plan.Node_UNIQUE: 85 pname = "Unique" 86 case plan.Node_WINDOW: 87 pname = "Window" 88 case plan.Node_BROADCAST: 89 pname = "Broadcast" 90 case plan.Node_SPLIT: 91 pname = "Split" 92 case plan.Node_GATHER: 93 pname = "Gather" 94 case plan.Node_ASSERT: 95 pname = "Assert" 96 case plan.Node_INSERT: 97 pname = "Insert" 98 case plan.Node_UPDATE: 99 pname = "Update" 100 case plan.Node_DELETE: 101 pname = "Delete" 102 case plan.Node_INTERSECT: 103 pname = "Intersect" 104 case plan.Node_INTERSECT_ALL: 105 pname = "Intersect All" 106 case plan.Node_MINUS: 107 pname = "Minus" 108 case plan.Node_MINUS_ALL: 109 pname = "Minus All" 110 case plan.Node_FUNCTION_SCAN: 111 pname = ndesc.Node.TableDef.TblFunc.Name 112 default: 113 panic("error node type") 114 } 115 116 // Get Node's operator object info ,such as table, view 117 if options.Format == EXPLAIN_FORMAT_TEXT { 118 result += pname 119 switch ndesc.Node.NodeType { 120 case plan.Node_VALUE_SCAN: 121 result += " \"*VALUES*\" " 122 case plan.Node_TABLE_SCAN, plan.Node_FUNCTION_SCAN, plan.Node_EXTERNAL_SCAN, plan.Node_MATERIAL_SCAN, plan.Node_INSERT: 123 result += " on " 124 if ndesc.Node.ObjRef != nil { 125 result += ndesc.Node.ObjRef.GetSchemaName() + "." + ndesc.Node.ObjRef.GetObjName() 126 } else if ndesc.Node.TableDef != nil { 127 result += ndesc.Node.TableDef.GetName() 128 } 129 case plan.Node_UPDATE: 130 result += " on " 131 if ndesc.Node.UpdateCtx != nil { 132 first := true 133 for _, ctx := range ndesc.Node.UpdateCtx.Ref { 134 if !first { 135 result += ", " 136 } 137 result += ctx.SchemaName + "." + ctx.ObjName 138 if first { 139 first = false 140 } 141 } 142 } 143 case plan.Node_DELETE: 144 result += " on " 145 if ndesc.Node.DeleteCtx != nil { 146 first := true 147 for _, ctx := range ndesc.Node.DeleteCtx.Ref { 148 if !first { 149 result += ", " 150 } 151 result += ctx.SchemaName + "." + ctx.ObjName 152 if first { 153 first = false 154 } 155 } 156 } 157 } 158 } 159 160 // Get Costs info of Node 161 if options.Format == EXPLAIN_FORMAT_TEXT { 162 //result += " (cost=%.2f..%.2f rows=%.0f width=%f)" 163 164 if options.Verbose { 165 costDescImpl := &CostDescribeImpl{ 166 Stats: ndesc.Node.GetStats(), 167 } 168 costInfo, err := costDescImpl.GetDescription(ctx, options) 169 if err != nil { 170 return result, err 171 } 172 result += " " + costInfo 173 } 174 } else if options.Format == EXPLAIN_FORMAT_JSON { 175 return result, moerr.NewNYI(ctx, "explain format json") 176 } else if options.Format == EXPLAIN_FORMAT_DOT { 177 return result, moerr.NewNYI(ctx, "explain format dot") 178 } 179 return result, nil 180 } 181 182 func (ndesc *NodeDescribeImpl) GetActualAnalyzeInfo(ctx context.Context, options *ExplainOptions) (string, error) { 183 result := "Analyze: " 184 if ndesc.Node.AnalyzeInfo != nil { 185 impl := NewAnalyzeInfoDescribeImpl(ndesc.Node.AnalyzeInfo) 186 describe, err := impl.GetDescription(ctx, options) 187 if err != nil { 188 return result, err 189 } 190 result += describe 191 } else { 192 result += "timeConsumed=0ns waitTime=0ns inputRows=0 outputRows=0 inputSize=0 bytes outputSize:0 bytes, memorySize=0 bytes" 193 } 194 return result, nil 195 } 196 197 func (ndesc *NodeDescribeImpl) GetTableDef(ctx context.Context, options *ExplainOptions) (string, error) { 198 result := "Table: " 199 if ndesc.Node.NodeType == plan.Node_TABLE_SCAN { 200 tableDef := ndesc.Node.TableDef 201 result += "'" + tableDef.Name + "' (" 202 first := true 203 for i, col := range tableDef.Cols { 204 if !first { 205 result += ", " 206 } 207 first = false 208 //result += "'" + col.Name + "':" + col.Typ.Id.String() 209 result += strconv.Itoa(i) + ":'" + col.Name + "'" 210 } 211 result += ")" 212 } else { 213 panic("implement me") 214 } 215 return result, nil 216 } 217 218 func (ndesc *NodeDescribeImpl) GetExtraInfo(ctx context.Context, options *ExplainOptions) ([]string, error) { 219 lines := make([]string, 0) 220 // Get Sort list info 221 if len(ndesc.Node.OrderBy) > 0 { 222 orderByInfo, err := ndesc.GetOrderByInfo(ctx, options) 223 if err != nil { 224 return nil, err 225 } 226 lines = append(lines, orderByInfo) 227 } 228 229 // Get Join type info 230 if ndesc.Node.NodeType == plan.Node_JOIN { 231 joinTypeInfo, err := ndesc.GetJoinTypeInfo(ctx, options) 232 if err != nil { 233 return nil, err 234 } 235 lines = append(lines, joinTypeInfo) 236 } 237 238 // Get Join Condition info 239 if len(ndesc.Node.OnList) > 0 { 240 joinOnInfo, err := ndesc.GetJoinConditionInfo(ctx, options) 241 if err != nil { 242 return nil, err 243 } 244 lines = append(lines, joinOnInfo) 245 } 246 247 // Get Group key info 248 if len(ndesc.Node.GroupBy) > 0 { 249 groupByInfo, err := ndesc.GetGroupByInfo(ctx, options) 250 if err != nil { 251 return nil, err 252 } 253 lines = append(lines, groupByInfo) 254 } 255 256 // Get Aggregate function info 257 if len(ndesc.Node.AggList) > 0 { 258 aggListInfo, err := ndesc.GetAggregationInfo(ctx, options) 259 if err != nil { 260 return nil, err 261 } 262 lines = append(lines, aggListInfo) 263 } 264 265 // Get Filter list info 266 if len(ndesc.Node.FilterList) > 0 { 267 filterInfo, err := ndesc.GetFilterConditionInfo(ctx, options) 268 if err != nil { 269 return nil, err 270 } 271 lines = append(lines, filterInfo) 272 } 273 274 // Get Limit And Offset info 275 if ndesc.Node.Limit != nil { 276 var temp string 277 limitInfo, err := describeExpr(ctx, ndesc.Node.Limit, options) 278 if err != nil { 279 return nil, err 280 } 281 temp += "Limit: " + limitInfo 282 if ndesc.Node.Offset != nil { 283 offsetInfo, err := describeExpr(ctx, ndesc.Node.Offset, options) 284 if err != nil { 285 return nil, err 286 } 287 temp += ", Offset: " + offsetInfo 288 } 289 lines = append(lines, temp) 290 } 291 292 //if ndesc.Node.UpdateList != nil { 293 // updateListDesc := &UpdateListDescribeImpl{ 294 // UpdateList: ndesc.Node.UpdateList, 295 // } 296 // updatedesc, err := updateListDesc.GetDescription(options) 297 // if err != nil { 298 // return nil, err 299 // } 300 // lines = append(lines, "Set columns with("+updatedesc+")") 301 //} 302 return lines, nil 303 } 304 305 func (ndesc *NodeDescribeImpl) GetProjectListInfo(ctx context.Context, options *ExplainOptions) (string, error) { 306 result := "Output: " 307 exprs := NewExprListDescribeImpl(ndesc.Node.ProjectList) 308 describe, err := exprs.GetDescription(ctx, options) 309 if err != nil { 310 return result, err 311 } 312 result += describe 313 return result, nil 314 } 315 316 func (ndesc *NodeDescribeImpl) GetJoinTypeInfo(ctx context.Context, options *ExplainOptions) (string, error) { 317 result := "Join Type: " + ndesc.Node.JoinType.String() 318 return result, nil 319 } 320 321 func (ndesc *NodeDescribeImpl) GetJoinConditionInfo(ctx context.Context, options *ExplainOptions) (string, error) { 322 result := "Join Cond: " 323 exprs := NewExprListDescribeImpl(ndesc.Node.OnList) 324 describe, err := exprs.GetDescription(ctx, options) 325 if err != nil { 326 return result, err 327 } 328 result += describe 329 return result, nil 330 } 331 332 func (ndesc *NodeDescribeImpl) GetFilterConditionInfo(ctx context.Context, options *ExplainOptions) (string, error) { 333 result := "Filter Cond: " 334 if options.Format == EXPLAIN_FORMAT_TEXT { 335 first := true 336 for _, v := range ndesc.Node.FilterList { 337 if !first { 338 result += ", " 339 } 340 first = false 341 descV, err := describeExpr(ctx, v, options) 342 if err != nil { 343 return result, err 344 } 345 result += descV 346 } 347 } else if options.Format == EXPLAIN_FORMAT_JSON { 348 return result, moerr.NewNYI(ctx, "explain format json") 349 } else if options.Format == EXPLAIN_FORMAT_DOT { 350 return result, moerr.NewNYI(ctx, "explain format dot") 351 } 352 return result, nil 353 } 354 355 func (ndesc *NodeDescribeImpl) GetGroupByInfo(ctx context.Context, options *ExplainOptions) (string, error) { 356 result := "Group Key: " 357 if options.Format == EXPLAIN_FORMAT_TEXT { 358 first := true 359 for _, v := range ndesc.Node.GetGroupBy() { 360 if !first { 361 result += ", " 362 } 363 first = false 364 descV, err := describeExpr(ctx, v, options) 365 if err != nil { 366 return result, err 367 } 368 result += descV 369 } 370 } else if options.Format == EXPLAIN_FORMAT_JSON { 371 return result, moerr.NewNYI(ctx, "explain format json") 372 } else if options.Format == EXPLAIN_FORMAT_DOT { 373 return result, moerr.NewNYI(ctx, "explain format dot") 374 } 375 return result, nil 376 } 377 378 func (ndesc *NodeDescribeImpl) GetAggregationInfo(ctx context.Context, options *ExplainOptions) (string, error) { 379 result := "Aggregate Functions: " 380 if options.Format == EXPLAIN_FORMAT_TEXT { 381 first := true 382 for _, v := range ndesc.Node.GetAggList() { 383 if !first { 384 result += ", " 385 } 386 first = false 387 descV, err := describeExpr(ctx, v, options) 388 if err != nil { 389 return result, err 390 } 391 result += descV 392 } 393 } else if options.Format == EXPLAIN_FORMAT_JSON { 394 return result, moerr.NewNYI(ctx, "explain format json") 395 } else if options.Format == EXPLAIN_FORMAT_DOT { 396 return result, moerr.NewNYI(ctx, "explain format dot") 397 } 398 return result, nil 399 } 400 401 func (ndesc *NodeDescribeImpl) GetOrderByInfo(ctx context.Context, options *ExplainOptions) (string, error) { 402 var result string 403 if options.Format == EXPLAIN_FORMAT_TEXT { 404 result = "Sort Key: " 405 orderByDescImpl := NewOrderByDescribeImpl(ndesc.Node.OrderBy) 406 describe, err := orderByDescImpl.GetDescription(ctx, options) 407 if err != nil { 408 return result, err 409 } 410 result += describe 411 } else if options.Format == EXPLAIN_FORMAT_JSON { 412 return result, moerr.NewNYI(ctx, "explain format json") 413 } else if options.Format == EXPLAIN_FORMAT_DOT { 414 return result, moerr.NewNYI(ctx, "explain format dot") 415 } 416 return result, nil 417 } 418 419 var _ NodeElemDescribe = &CostDescribeImpl{} 420 var _ NodeElemDescribe = &ExprListDescribeImpl{} 421 var _ NodeElemDescribe = &OrderByDescribeImpl{} 422 var _ NodeElemDescribe = &WinSpecDescribeImpl{} 423 var _ NodeElemDescribe = &RowsetDataDescribeImpl{} 424 var _ NodeElemDescribe = &UpdateCtxsDescribeImpl{} 425 var _ NodeElemDescribe = &AnalyzeInfoDescribeImpl{} 426 427 type AnalyzeInfoDescribeImpl struct { 428 AnalyzeInfo *plan.AnalyzeInfo 429 } 430 431 func NewAnalyzeInfoDescribeImpl(analyze *plan.AnalyzeInfo) *AnalyzeInfoDescribeImpl { 432 return &AnalyzeInfoDescribeImpl{ 433 AnalyzeInfo: analyze, 434 } 435 } 436 437 func (a AnalyzeInfoDescribeImpl) GetDescription(ctx context.Context, options *ExplainOptions) (string, error) { 438 result := "timeConsumed=" + strconv.FormatInt(a.AnalyzeInfo.TimeConsumed, 10) + "ns" + 439 " waitTime=" + strconv.FormatInt(a.AnalyzeInfo.WaitTimeConsumed, 10) + "ns" + 440 " inputRows=" + strconv.FormatInt(a.AnalyzeInfo.InputRows, 10) + 441 " outputRows=" + strconv.FormatInt(a.AnalyzeInfo.OutputRows, 10) + 442 " inputSize=" + strconv.FormatInt(a.AnalyzeInfo.InputSize, 10) + "bytes" + 443 " outputSize=" + strconv.FormatInt(a.AnalyzeInfo.OutputSize, 10) + "bytes" + 444 " memorySize=" + strconv.FormatInt(a.AnalyzeInfo.MemorySize, 10) + "bytes" 445 return result, nil 446 } 447 448 type CostDescribeImpl struct { 449 Stats *plan.Stats 450 } 451 452 func (c *CostDescribeImpl) GetDescription(ctx context.Context, options *ExplainOptions) (string, error) { 453 var result string 454 if c.Stats == nil { 455 result = " (cost=0)" 456 //result = " (cost=%.2f..%.2f rows=%.2f ndv=%.2f rowsize=%.f)" 457 } else { 458 var blockNumStr, hashmapSizeStr, selString string 459 if c.Stats.BlockNum > 0 { 460 blockNumStr = " blockNum=" + strconv.FormatInt(int64(c.Stats.BlockNum), 10) 461 selString = " selectivity=" + strconv.FormatFloat(c.Stats.Selectivity, 'f', 2, 64) 462 } 463 if c.Stats.HashmapSize > 0 { 464 hashmapSizeStr = " hashmapSize=" + strconv.FormatFloat(c.Stats.HashmapSize, 'f', 2, 64) 465 } 466 467 result = " (cost=" + strconv.FormatFloat(c.Stats.Cost, 'f', 2, 64) + 468 " outcnt=" + strconv.FormatFloat(c.Stats.Outcnt, 'f', 2, 64) + 469 blockNumStr + selString + hashmapSizeStr + ")" 470 } 471 return result, nil 472 } 473 474 type ExprListDescribeImpl struct { 475 ExprList []*plan.Expr // ProjectList,OnList,FilterList,GroupBy,GroupingSet and so on 476 } 477 478 func NewExprListDescribeImpl(ExprList []*plan.Expr) *ExprListDescribeImpl { 479 return &ExprListDescribeImpl{ 480 ExprList: ExprList, 481 } 482 } 483 484 func (e *ExprListDescribeImpl) GetDescription(ctx context.Context, options *ExplainOptions) (string, error) { 485 first := true 486 var result string 487 if options.Format == EXPLAIN_FORMAT_TEXT { 488 for _, v := range e.ExprList { 489 if !first { 490 result += ", " 491 } 492 first = false 493 descV, err := describeExpr(ctx, v, options) 494 if err != nil { 495 return result, err 496 } 497 result += descV 498 } 499 } else if options.Format == EXPLAIN_FORMAT_JSON { 500 return result, moerr.NewNYI(ctx, "explain format json") 501 } else if options.Format == EXPLAIN_FORMAT_DOT { 502 return result, moerr.NewNYI(ctx, "explain format dot") 503 } 504 return result, nil 505 } 506 507 type OrderByDescribeImpl struct { 508 OrderBy []*plan.OrderBySpec 509 } 510 511 func NewOrderByDescribeImpl(OrderBy []*plan.OrderBySpec) *OrderByDescribeImpl { 512 return &OrderByDescribeImpl{ 513 OrderBy: OrderBy, 514 } 515 } 516 517 func (o *OrderByDescribeImpl) GetDescription(ctx context.Context, options *ExplainOptions) (string, error) { 518 var result string 519 if options.Format == EXPLAIN_FORMAT_TEXT || options.Format == EXPLAIN_FORMAT_JSON { 520 first := true 521 for _, v := range o.OrderBy { 522 if !first { 523 result += ", " 524 } 525 first = false 526 descExpr, err := describeExpr(ctx, v.Expr, options) 527 if err != nil { 528 return result, err 529 } 530 result += descExpr 531 532 flagKey := int32(v.Flag) 533 orderbyFlag := plan.OrderBySpec_OrderByFlag_name[flagKey] 534 result += " " + orderbyFlag 535 } 536 return result, nil 537 } else if options.Format == EXPLAIN_FORMAT_DOT { 538 return "", moerr.NewNYI(ctx, "explain format dot") 539 } 540 return result, nil 541 } 542 543 type WinSpecDescribeImpl struct { 544 WinSpec *plan.WindowSpec 545 } 546 547 func (w *WinSpecDescribeImpl) GetDescription(ctx context.Context, options *ExplainOptions) (string, error) { 548 // TODO implement me 549 panic("implement me") 550 } 551 552 type RowsetDataDescribeImpl struct { 553 RowsetData *plan.RowsetData 554 } 555 556 func (r *RowsetDataDescribeImpl) GetDescription(ctx context.Context, options *ExplainOptions) (string, error) { 557 result := "Value:" 558 if r.RowsetData == nil { 559 return result, nil 560 } 561 562 first := true 563 for index := range r.RowsetData.Cols { 564 if !first { 565 result += ", " 566 } 567 first = false 568 result += "\"*VALUES*\".column" + strconv.Itoa(index+1) 569 } 570 return result, nil 571 } 572 573 type UpdateCtxsDescribeImpl struct { 574 UpdateCtx *plan.UpdateCtx 575 } 576 577 func (u *UpdateCtxsDescribeImpl) GetDescription(ctx context.Context, options *ExplainOptions) (string, error) { 578 result := "Update Columns: " 579 first := true 580 for i, ctx := range u.UpdateCtx.Ref { 581 if u.UpdateCtx.UpdateCol[i] != nil { 582 for colName := range u.UpdateCtx.UpdateCol[i].Map { 583 if !first { 584 result += ", " 585 } else { 586 first = false 587 } 588 result += ctx.SchemaName + "." + ctx.ObjName + "." + colName 589 } 590 } 591 } 592 return result, nil 593 }