github.com/matrixorigin/matrixone@v1.2.0/pkg/sql/plan/explain/marshal_query.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  	"bytes"
    19  	"context"
    20  	"fmt"
    21  	"strconv"
    22  	"strings"
    23  
    24  	"github.com/matrixorigin/matrixone/pkg/common/moerr"
    25  	"github.com/matrixorigin/matrixone/pkg/pb/plan"
    26  	"github.com/matrixorigin/matrixone/pkg/util/trace/impl/motrace/statistic"
    27  )
    28  
    29  var errUnsupportedNodeType = "Unsupported node type when plan is serialized to json"
    30  
    31  // The global variable is used to serialize plan and avoid objects being repeatedly created
    32  var MarshalPlanOptions = ExplainOptions{
    33  	Verbose: true,
    34  	Analyze: true,
    35  	Format:  EXPLAIN_FORMAT_TEXT,
    36  }
    37  
    38  func ConvertNode(ctx context.Context, node *plan.Node, options *ExplainOptions) (*Node, error) {
    39  	marshalNodeImpl := NewMarshalNodeImpl(node)
    40  	newNode := &Node{
    41  		NodeId:     strconv.FormatInt(int64(node.NodeId), 10),
    42  		Statistics: marshalNodeImpl.GetStatistics(ctx, options),
    43  		Stats:      marshalNodeImpl.GetStats(),
    44  		TotalStats: marshalNodeImpl.GetTotalStats(),
    45  	}
    46  	name, err := marshalNodeImpl.GetNodeName(ctx)
    47  	if err != nil {
    48  		return nil, err
    49  	}
    50  	newNode.Name = name
    51  
    52  	title, err := marshalNodeImpl.GetNodeTitle(ctx, options)
    53  	if err != nil {
    54  		return nil, err
    55  	}
    56  	newNode.Title = title
    57  
    58  	labels, err := marshalNodeImpl.GetNodeLabels(ctx, options)
    59  	if err != nil {
    60  		return nil, err
    61  	}
    62  	newNode.Labels = labels
    63  	return newNode, nil
    64  }
    65  
    66  type MarshalNode interface {
    67  	GetNodeName(ctx context.Context) (string, error)
    68  	GetNodeTitle(ctx context.Context, options *ExplainOptions) (string, error)
    69  	GetNodeLabels(ctx context.Context, options *ExplainOptions) ([]Label, error)
    70  	GetStatistics(ctx context.Context, options *ExplainOptions) Statistics
    71  	GetStats() Stats
    72  	GetTotalStats() TotalStats
    73  }
    74  
    75  type MarshalNodeImpl struct {
    76  	node *plan.Node
    77  }
    78  
    79  func NewMarshalNodeImpl(node *plan.Node) *MarshalNodeImpl {
    80  	return &MarshalNodeImpl{
    81  		node: node,
    82  	}
    83  }
    84  
    85  func (m MarshalNodeImpl) GetStats() Stats {
    86  	if m.node.Stats != nil {
    87  		var hashmapSize float64
    88  		if m.node.Stats.HashmapStats != nil {
    89  			hashmapSize = m.node.Stats.HashmapStats.HashmapSize
    90  		}
    91  		return Stats{
    92  			BlockNum:    m.node.Stats.BlockNum,
    93  			Cost:        m.node.Stats.Cost,
    94  			Outcnt:      m.node.Stats.Outcnt,
    95  			HashmapSize: hashmapSize,
    96  			Rowsize:     m.node.Stats.Rowsize,
    97  		}
    98  	} else {
    99  		return Stats{}
   100  	}
   101  }
   102  
   103  func (m MarshalNodeImpl) GetNodeName(ctx context.Context) (string, error) {
   104  	// Get the Node Name
   105  	if value, ok := nodeTypeToNameMap[m.node.NodeType]; ok {
   106  		return value, nil
   107  	} else {
   108  		return "", moerr.NewInternalError(ctx, errUnsupportedNodeType)
   109  	}
   110  }
   111  
   112  func (m MarshalNodeImpl) GetNodeTitle(ctx context.Context, options *ExplainOptions) (string, error) {
   113  	//var result string
   114  	buf := bytes.NewBuffer(make([]byte, 0, 400))
   115  	var err error
   116  	switch m.node.NodeType {
   117  	case plan.Node_TABLE_SCAN, plan.Node_EXTERNAL_SCAN, plan.Node_MATERIAL_SCAN, plan.Node_SOURCE_SCAN:
   118  		//"title" : "SNOWFLAKE_SAMPLE_DATA.TPCDS_SF10TCL.DATE_DIM",
   119  		if m.node.ObjRef != nil {
   120  			buf.WriteString(m.node.ObjRef.GetSchemaName() + "." + m.node.ObjRef.GetObjName())
   121  		} else if m.node.TableDef != nil {
   122  			buf.WriteString(m.node.TableDef.GetName())
   123  		} else {
   124  			return "", moerr.NewInvalidInput(ctx, "Table definition not found when plan is serialized to json")
   125  		}
   126  	case plan.Node_DELETE:
   127  		if m.node.DeleteCtx != nil {
   128  			ctx := m.node.DeleteCtx.Ref
   129  			buf.WriteString(ctx.SchemaName + "." + ctx.ObjName)
   130  		} else {
   131  			return "", moerr.NewInternalError(ctx, "Table definition not found when plan is serialized to json")
   132  		}
   133  	case plan.Node_INSERT:
   134  		if m.node.InsertCtx != nil {
   135  			ctx := m.node.InsertCtx.Ref
   136  			buf.WriteString(ctx.SchemaName + "." + ctx.ObjName)
   137  		} else {
   138  			return "", moerr.NewInternalError(ctx, "Table definition not found when plan is serialized to json")
   139  		}
   140  	case plan.Node_PROJECT, plan.Node_VALUE_SCAN, plan.Node_UNION, plan.Node_UNION_ALL,
   141  		plan.Node_INTERSECT, plan.Node_INTERSECT_ALL, plan.Node_MINUS:
   142  		//"title" : "STORE.S_STORE_NAME,STORE.S_STORE_ID,WSS.D_WEEK_SEQ"
   143  		exprs := NewExprListDescribeImpl(m.node.ProjectList)
   144  		err = exprs.GetDescription(ctx, options, buf)
   145  		if err != nil {
   146  			return "", err
   147  		}
   148  	case plan.Node_AGG:
   149  		// "SUM(IFF(DATE_DIM.D_DAY_NAME = 'Sunday', STORE_SALES.SS_SALES_PRICE, null))"
   150  		exprs := NewExprListDescribeImpl(m.node.AggList)
   151  		err = exprs.GetDescription(ctx, options, buf)
   152  		if err != nil {
   153  			return "", err
   154  		}
   155  	case plan.Node_FILTER:
   156  		//"title" : "(D_0.D_MONTH_SEQ >= 1189) AND (D_0.D_MONTH_SEQ <= 1200)",
   157  		exprs := NewExprListDescribeImpl(m.node.FilterList)
   158  		err = exprs.GetDescription(ctx, options, buf)
   159  		if err != nil {
   160  			return "", err
   161  		}
   162  	case plan.Node_JOIN:
   163  		//"title" : "(DATE_DIM.D_DATE_SK = STORE_SALES.SS_SOLD_DATE_SK)",
   164  		exprs := NewExprListDescribeImpl(m.node.OnList)
   165  		err = exprs.GetDescription(ctx, options, buf)
   166  		if err != nil {
   167  			return "", err
   168  		}
   169  	case plan.Node_SORT:
   170  		//"title" : "STORE.S_STORE_NAME ASC NULLS LAST,STORE.S_STORE_ID ASC NULLS LAST,WSS.D_WEEK_SEQ ASC NULLS LAST",
   171  		orderByDescImpl := NewOrderByDescribeImpl(m.node.OrderBy)
   172  		err = orderByDescImpl.GetDescription(ctx, options, buf)
   173  		if err != nil {
   174  			return "", err
   175  		}
   176  	case plan.Node_PRE_INSERT:
   177  		return "preinsert", nil
   178  	case plan.Node_PRE_INSERT_UK:
   179  		return "preinsert_uk", nil
   180  	case plan.Node_PRE_INSERT_SK:
   181  		return "preinsert_sk", nil
   182  	case plan.Node_PRE_DELETE:
   183  		return "predelete", nil
   184  	case plan.Node_SINK:
   185  		return "sink", nil
   186  	case plan.Node_SINK_SCAN:
   187  		return "sink_scan", nil
   188  	case plan.Node_RECURSIVE_SCAN:
   189  		return "recursive_scan", nil
   190  	case plan.Node_RECURSIVE_CTE:
   191  		return "cte_scan", nil
   192  	case plan.Node_ON_DUPLICATE_KEY:
   193  		return "on_duplicate_key", nil
   194  	case plan.Node_LOCK_OP:
   195  		return "lock_op", nil
   196  	case plan.Node_ASSERT:
   197  		return "assert", nil
   198  	case plan.Node_BROADCAST:
   199  		return "broadcast", nil
   200  	case plan.Node_SPLIT:
   201  		return "split", nil
   202  	case plan.Node_GATHER:
   203  		return "gather", nil
   204  	case plan.Node_REPLACE:
   205  		return "replace", nil
   206  	case plan.Node_TIME_WINDOW:
   207  		return "time_window", nil
   208  	case plan.Node_FILL:
   209  		return "fill", nil
   210  	case plan.Node_PARTITION:
   211  		return "partition", nil
   212  	case plan.Node_FUNCTION_SCAN:
   213  		//"title" : "SNOWFLAKE_SAMPLE_DATA.TPCDS_SF10TCL.DATE_DIM",
   214  		if m.node.TableDef != nil && m.node.TableDef.TblFunc != nil {
   215  			fmt.Fprintf(buf, "Table Function[%s]", m.node.TableDef.TblFunc.Name)
   216  		} else {
   217  			return "", moerr.NewInvalidInput(ctx, "Table definition not found when plan is serialized to json")
   218  		}
   219  	case plan.Node_FUZZY_FILTER:
   220  		return "fuzzy_filter", nil
   221  	case plan.Node_SAMPLE:
   222  		return "sample", nil
   223  	case plan.Node_UNKNOWN:
   224  		return "unknown", nil
   225  	case plan.Node_DISTINCT:
   226  		return "distinct", nil
   227  	case plan.Node_UNIQUE:
   228  		return "unique", nil
   229  	case plan.Node_MINUS_ALL:
   230  		return "minus_all", nil
   231  	case plan.Node_EXTERNAL_FUNCTION:
   232  		return "external_function", nil
   233  	case plan.Node_WINDOW:
   234  		return "window", nil
   235  	case plan.Node_MATERIAL:
   236  		return "mterial", nil
   237  	default:
   238  		return "", moerr.NewInternalError(ctx, errUnsupportedNodeType)
   239  	}
   240  	return strings.TrimSpace(buf.String()), nil
   241  }
   242  
   243  func (m MarshalNodeImpl) GetNodeLabels(ctx context.Context, options *ExplainOptions) ([]Label, error) {
   244  	labels := make([]Label, 0)
   245  
   246  	// 1. Handling unique label information for different nodes
   247  	switch m.node.NodeType {
   248  	case plan.Node_TABLE_SCAN, plan.Node_EXTERNAL_SCAN, plan.Node_MATERIAL_SCAN, plan.Node_SOURCE_SCAN:
   249  		tableDef := m.node.TableDef
   250  		objRef := m.node.ObjRef
   251  		fullTableName := ""
   252  		if objRef != nil {
   253  			fullTableName += objRef.GetSchemaName() + "." + objRef.GetObjName()
   254  		} else if tableDef != nil {
   255  			fullTableName += tableDef.GetName()
   256  		} else {
   257  			return nil, moerr.NewInternalError(ctx, "Table definition not found when plan is serialized to json")
   258  		}
   259  
   260  		labels = append(labels, Label{
   261  			Name:  Label_Table_Name, //"Full table name",
   262  			Value: fullTableName,
   263  		})
   264  
   265  		// "name" : "Columns (2 / 28)",
   266  		columns := GetTableColsLableValue(ctx, tableDef.Cols, options)
   267  
   268  		labels = append(labels, Label{
   269  			Name:  Label_Table_Columns, //"Columns",
   270  			Value: columns,
   271  		})
   272  
   273  		labels = append(labels, Label{
   274  			Name:  Label_Total_Columns, //"Total columns",
   275  			Value: len(tableDef.Name2ColIndex),
   276  		})
   277  
   278  		labels = append(labels, Label{
   279  			Name:  Label_Scan_Columns, //"Scan columns",
   280  			Value: len(tableDef.Cols),
   281  		})
   282  
   283  		if len(m.node.BlockFilterList) > 0 {
   284  			value, err := GetExprsLabelValue(ctx, m.node.BlockFilterList, options)
   285  			if err != nil {
   286  				return nil, err
   287  			}
   288  			labels = append(labels, Label{
   289  				Name:  Label_Block_Filter_Conditions, // "Block Filter conditions",
   290  				Value: value,
   291  			})
   292  		}
   293  	case plan.Node_FUNCTION_SCAN:
   294  		tableDef := m.node.TableDef
   295  		fullTableName := ""
   296  		if tableDef != nil && tableDef.TblFunc != nil {
   297  			fullTableName += tableDef.TblFunc.GetName()
   298  		} else {
   299  			return nil, moerr.NewInternalError(ctx, "Table Function definition not found when plan is serialized to json")
   300  		}
   301  
   302  		labels = append(labels, Label{
   303  			Name:  Label_Table_Name, //"Full table name",
   304  			Value: fullTableName,
   305  		})
   306  
   307  		// "name" : "Columns (2 / 28)",
   308  		columns := GetTableColsLableValue(ctx, tableDef.Cols, options)
   309  
   310  		labels = append(labels, Label{
   311  			Name:  Label_Table_Columns, //"Columns",
   312  			Value: columns,
   313  		})
   314  
   315  		labels = append(labels, Label{
   316  			Name:  Label_Total_Columns, //"Total columns",
   317  			Value: len(tableDef.Name2ColIndex),
   318  		})
   319  
   320  		labels = append(labels, Label{
   321  			Name:  Label_Scan_Columns, //"Scan columns",
   322  			Value: len(tableDef.Cols),
   323  		})
   324  
   325  		if len(m.node.BlockFilterList) > 0 {
   326  			value, err := GetExprsLabelValue(ctx, m.node.BlockFilterList, options)
   327  			if err != nil {
   328  				return nil, err
   329  			}
   330  			labels = append(labels, Label{
   331  				Name:  Label_Block_Filter_Conditions, // "Block Filter conditions",
   332  				Value: value,
   333  			})
   334  		}
   335  	case plan.Node_INSERT:
   336  		objRef := m.node.InsertCtx.Ref
   337  		fullTableName := ""
   338  		if objRef != nil {
   339  			fullTableName += objRef.GetSchemaName() + "." + objRef.GetObjName()
   340  		} else {
   341  			return nil, moerr.NewInternalError(ctx, "Table definition not found when plan is serialized to json")
   342  		}
   343  
   344  		labels = append(labels, Label{
   345  			Name:  Label_Table_Name, //"Full table name",
   346  			Value: fullTableName,
   347  		})
   348  	case plan.Node_DELETE:
   349  		if m.node.DeleteCtx != nil {
   350  			deleteTableNames := GetDeleteTableLabelValue(m.node.DeleteCtx)
   351  			labels = append(labels, Label{
   352  				Name:  Label_Table_Name, //"Full table name",
   353  				Value: deleteTableNames,
   354  			})
   355  		} else {
   356  			return nil, moerr.NewInvalidInput(ctx, "Table definition not found when plan is serialized to json")
   357  		}
   358  	case plan.Node_PROJECT:
   359  		value, err := GetExprsLabelValue(ctx, m.node.ProjectList, options)
   360  		if err != nil {
   361  			return nil, err
   362  		}
   363  		labels = append(labels, Label{
   364  			Name:  Label_List_Expression, //"List of expressions",
   365  			Value: value,
   366  		})
   367  	case plan.Node_AGG:
   368  		// Get Group key info
   369  		if len(m.node.GroupBy) > 0 {
   370  			// Get Grouping Key
   371  			value, err := GetExprsLabelValue(ctx, m.node.GroupBy, options)
   372  			if err != nil {
   373  				return nil, err
   374  			}
   375  			labels = append(labels, Label{
   376  				Name:  Label_Grouping_Keys, //"Grouping keys",
   377  				Value: value,
   378  			})
   379  		}
   380  
   381  		// Get Aggregate function info
   382  		if len(m.node.AggList) > 0 {
   383  			value, err := GetExprsLabelValue(ctx, m.node.AggList, options)
   384  			if err != nil {
   385  				return nil, err
   386  			}
   387  			labels = append(labels, Label{
   388  				Name:  Label_Agg_Functions, //"Aggregate functions",
   389  				Value: value,
   390  			})
   391  		}
   392  	case plan.Node_FILTER:
   393  		value, err := GetExprsLabelValue(ctx, m.node.FilterList, options)
   394  		if err != nil {
   395  			return nil, err
   396  		}
   397  		labels = append(labels, Label{
   398  			Name:  Label_Filter_Conditions, //"Filter conditions",
   399  			Value: value,
   400  		})
   401  	case plan.Node_JOIN:
   402  		// Get Join type
   403  		labels = append(labels, Label{
   404  			Name:  Label_Join_Type, //"Join type",
   405  			Value: m.node.JoinType.String(),
   406  		})
   407  
   408  		// Get Join Condition info
   409  		if len(m.node.OnList) > 0 {
   410  			value, err := GetExprsLabelValue(ctx, m.node.OnList, options)
   411  			if err != nil {
   412  				return nil, err
   413  			}
   414  			labels = append(labels, Label{
   415  				Name:  Label_Join_Conditions, //"Join conditions",
   416  				Value: value,
   417  			})
   418  		}
   419  		labels = append(labels, Label{
   420  			Name:  Label_Left_NodeId, //"Left node id",
   421  			Value: m.node.Children[0],
   422  		})
   423  		labels = append(labels, Label{
   424  			Name:  Label_Right_NodeId, //"Right node id",
   425  			Value: m.node.Children[1],
   426  		})
   427  	case plan.Node_SORT:
   428  		result, err := GetOrderByLabelValue(ctx, m.node.OrderBy, options)
   429  		if err != nil {
   430  			return nil, err
   431  		}
   432  		labels = append(labels, Label{
   433  			Name:  Label_Sort_Keys, //"Sort keys",
   434  			Value: result,
   435  		})
   436  	case plan.Node_VALUE_SCAN:
   437  		value, err := GetExprsLabelValue(ctx, m.node.ProjectList, options)
   438  		if err != nil {
   439  			return nil, err
   440  		}
   441  		labels = append(labels, Label{
   442  			Name:  Label_List_Values, //"List of values",
   443  			Value: value,
   444  		})
   445  
   446  		if len(m.node.BlockFilterList) > 0 {
   447  			value, err = GetExprsLabelValue(ctx, m.node.BlockFilterList, options)
   448  			if err != nil {
   449  				return nil, err
   450  			}
   451  			labels = append(labels, Label{
   452  				Name:  Label_Block_Filter_Conditions, // "Block Filter conditions",
   453  				Value: value,
   454  			})
   455  		}
   456  	case plan.Node_UNION:
   457  		value, err := GetExprsLabelValue(ctx, m.node.ProjectList, options)
   458  		if err != nil {
   459  			return nil, err
   460  		}
   461  		labels = append(labels, Label{
   462  			Name:  Label_Union_Expressions, //"Union expressions",
   463  			Value: value,
   464  		})
   465  	case plan.Node_UNION_ALL:
   466  		value, err := GetExprsLabelValue(ctx, m.node.ProjectList, options)
   467  		if err != nil {
   468  			return nil, err
   469  		}
   470  		labels = append(labels, Label{
   471  			Name:  Label_Union_All_Expressions, // "Union all expressions",
   472  			Value: value,
   473  		})
   474  	case plan.Node_INTERSECT:
   475  		value, err := GetExprsLabelValue(ctx, m.node.ProjectList, options)
   476  		if err != nil {
   477  			return nil, err
   478  		}
   479  		labels = append(labels, Label{
   480  			Name:  Label_Intersect_Expressions, //"Intersect expressions",
   481  			Value: value,
   482  		})
   483  	case plan.Node_INTERSECT_ALL:
   484  		value, err := GetExprsLabelValue(ctx, m.node.ProjectList, options)
   485  		if err != nil {
   486  			return nil, err
   487  		}
   488  		labels = append(labels, Label{
   489  			Name:  Label_Intersect_All_Expressions, //"Intersect All expressions",
   490  			Value: value,
   491  		})
   492  	case plan.Node_MINUS:
   493  		value, err := GetExprsLabelValue(ctx, m.node.ProjectList, options)
   494  		if err != nil {
   495  			return nil, err
   496  		}
   497  		labels = append(labels, Label{
   498  			Name:  Label_Minus_Expressions, //"Minus expressions",
   499  			Value: value,
   500  		})
   501  	case plan.Node_PRE_INSERT:
   502  		labels = append(labels, Label{
   503  			Name:  Label_Pre_Insert, //"pre insert",
   504  			Value: []string{},
   505  		})
   506  	case plan.Node_PRE_INSERT_UK:
   507  		labels = append(labels, Label{
   508  			Name:  Label_Pre_InsertUk, //"pre insert uk",
   509  			Value: []string{},
   510  		})
   511  	case plan.Node_PRE_INSERT_SK:
   512  		labels = append(labels, Label{
   513  			Name:  Label_Pre_InsertSk, //"pre insert sk",
   514  			Value: []string{},
   515  		})
   516  	case plan.Node_PRE_DELETE:
   517  		labels = append(labels, Label{
   518  			Name:  Label_Pre_Delete, //"pre delete",
   519  			Value: []string{},
   520  		})
   521  	case plan.Node_SINK:
   522  		labels = append(labels, Label{
   523  			Name:  Label_Sink, //"sink",
   524  			Value: []string{},
   525  		})
   526  	case plan.Node_SINK_SCAN:
   527  		labels = append(labels, Label{
   528  			Name:  Label_Sink_Scan, //"sink scan",
   529  			Value: []string{},
   530  		})
   531  	case plan.Node_RECURSIVE_SCAN:
   532  		labels = append(labels, Label{
   533  			Name:  Label_Recursive_SCAN, //"sink scan",
   534  			Value: []string{},
   535  		})
   536  	case plan.Node_RECURSIVE_CTE:
   537  		labels = append(labels, Label{
   538  			Name:  Label_Recursive_SCAN, //"sink scan",
   539  			Value: []string{},
   540  		})
   541  	case plan.Node_LOCK_OP:
   542  		labels = append(labels, Label{
   543  			Name:  Label_Lock_Op, //"lock op",
   544  			Value: []string{},
   545  		})
   546  	case plan.Node_TIME_WINDOW:
   547  		labels = append(labels, Label{
   548  			Name:  Label_Time_Window,
   549  			Value: []string{},
   550  		})
   551  	case plan.Node_PARTITION:
   552  		labels = append(labels, Label{
   553  			Name:  Label_Partition,
   554  			Value: []string{},
   555  		})
   556  	case plan.Node_BROADCAST:
   557  		labels = append(labels, Label{
   558  			Name:  Label_Boardcast,
   559  			Value: []string{},
   560  		})
   561  	case plan.Node_SPLIT:
   562  		labels = append(labels, Label{
   563  			Name:  Label_Split,
   564  			Value: []string{},
   565  		})
   566  	case plan.Node_GATHER:
   567  		labels = append(labels, Label{
   568  			Name:  Label_Gather,
   569  			Value: []string{},
   570  		})
   571  	case plan.Node_ASSERT:
   572  		labels = append(labels, Label{
   573  			Name:  Label_Assert,
   574  			Value: []string{},
   575  		})
   576  	case plan.Node_ON_DUPLICATE_KEY:
   577  		labels = append(labels, Label{
   578  			Name:  Label_On_Duplicate_Key,
   579  			Value: []string{},
   580  		})
   581  	case plan.Node_FUZZY_FILTER:
   582  		labels = append(labels, Label{
   583  			Name:  Label_Fuzzy_Filter,
   584  			Value: []string{},
   585  		})
   586  	case plan.Node_EXTERNAL_FUNCTION:
   587  		labels = append(labels, Label{
   588  			Name:  Label_External_Function,
   589  			Value: []string{},
   590  		})
   591  	case plan.Node_FILL:
   592  		labels = append(labels, Label{
   593  			Name:  Label_Fill,
   594  			Value: []string{},
   595  		})
   596  	case plan.Node_DISTINCT:
   597  		labels = append(labels, Label{
   598  			Name:  Label_Distinct,
   599  			Value: []string{},
   600  		})
   601  	case plan.Node_SAMPLE:
   602  		labels = append(labels, Label{
   603  			Name:  Label_Sample,
   604  			Value: []string{},
   605  		})
   606  	case plan.Node_WINDOW:
   607  		labels = append(labels, Label{
   608  			Name:  Label_Window,
   609  			Value: []string{},
   610  		})
   611  	case plan.Node_MINUS_ALL:
   612  		labels = append(labels, Label{
   613  			Name:  Label_Minus_All,
   614  			Value: []string{},
   615  		})
   616  	case plan.Node_UNIQUE:
   617  		labels = append(labels, Label{
   618  			Name:  Label_Unique,
   619  			Value: []string{},
   620  		})
   621  	case plan.Node_REPLACE:
   622  		labels = append(labels, Label{
   623  			Name:  Label_Replace,
   624  			Value: []string{},
   625  		})
   626  	case plan.Node_UNKNOWN:
   627  		labels = append(labels, Label{
   628  			Name:  Label_Unknown,
   629  			Value: []string{},
   630  		})
   631  	case plan.Node_MATERIAL:
   632  		labels = append(labels, Label{
   633  			Name:  Label_Meterial,
   634  			Value: []string{},
   635  		})
   636  	default:
   637  		return nil, moerr.NewInternalError(ctx, errUnsupportedNodeType)
   638  	}
   639  
   640  	// 2. handle shared label information for all nodes, such as filter conditions
   641  	if len(m.node.FilterList) > 0 && m.node.NodeType != plan.Node_FILTER {
   642  		value, err := GetExprsLabelValue(ctx, m.node.FilterList, options)
   643  		if err != nil {
   644  			return nil, err
   645  		}
   646  		labels = append(labels, Label{
   647  			Name:  Label_Filter_Conditions, // "Filter conditions",
   648  			Value: value,
   649  		})
   650  	}
   651  
   652  	// 3. handle `Limit` and `Offset` label information for all nodes
   653  	if m.node.Limit != nil {
   654  		buf := bytes.NewBuffer(make([]byte, 0, 80))
   655  		err := describeExpr(ctx, m.node.Limit, options, buf)
   656  		if err != nil {
   657  			return nil, err
   658  		}
   659  		labels = append(labels, Label{
   660  			Name:  Label_Row_Number, //"Number of rows",
   661  			Value: buf.String(),
   662  		})
   663  
   664  		if m.node.Offset != nil {
   665  			buf.Reset()
   666  			err := describeExpr(ctx, m.node.Offset, options, buf)
   667  			if err != nil {
   668  				return nil, err
   669  			}
   670  			labels = append(labels, Label{
   671  				Name:  Label_Offset, // "Offset",
   672  				Value: buf.String(),
   673  			})
   674  		} else {
   675  			labels = append(labels, Label{
   676  				Name:  Label_Offset, // "Offset",
   677  				Value: 0,
   678  			})
   679  		}
   680  	}
   681  	return labels, nil
   682  }
   683  
   684  const TimeConsumed = "Time Consumed"
   685  const WaitTime = "Wait Time"
   686  const ScanTime = "Scan Time"
   687  const InsertTime = "Insert Time"
   688  
   689  const InputRows = "Input Rows"
   690  const OutputRows = "Output Rows"
   691  const InputSize = "Input Size"
   692  const OutputSize = "Output Size"
   693  const MemorySize = "Memory Size"
   694  const DiskIO = "Disk IO"
   695  const S3IOByte = "S3 IO Byte"
   696  const S3IOInputCount = "S3 IO Input Count"
   697  const S3IOOutputCount = "S3 IO Output Count"
   698  const Network = "Network"
   699  
   700  func GetStatistic4Trace(ctx context.Context, node *plan.Node, options *ExplainOptions) (s statistic.StatsArray) {
   701  	s.Reset()
   702  	if options.Analyze && node.AnalyzeInfo != nil {
   703  		analyzeInfo := node.AnalyzeInfo
   704  		s.WithTimeConsumed(float64(analyzeInfo.TimeConsumed)).
   705  			WithMemorySize(float64(analyzeInfo.MemorySize)).
   706  			WithS3IOInputCount(float64(analyzeInfo.S3IOInputCount)).
   707  			WithS3IOOutputCount(float64(analyzeInfo.S3IOOutputCount))
   708  	}
   709  	return
   710  }
   711  
   712  // GetInputRowsAndInputSize return plan.Node AnalyzeInfo InputRows and InputSize.
   713  // migrate ExplainData.StatisticsRead to here
   714  func GetInputRowsAndInputSize(ctx context.Context, node *plan.Node, options *ExplainOptions) (rows int64, size int64) {
   715  	if options.Analyze && node.AnalyzeInfo != nil {
   716  		return node.AnalyzeInfo.InputRows, node.AnalyzeInfo.InputSize
   717  	}
   718  	return
   719  }
   720  
   721  func (m MarshalNodeImpl) GetStatistics(ctx context.Context, options *ExplainOptions) Statistics {
   722  	statistics := NewStatistics()
   723  	if options.Analyze && m.node.AnalyzeInfo != nil {
   724  		analyzeInfo := m.node.AnalyzeInfo
   725  		times := []StatisticValue{
   726  			{
   727  				Name:  TimeConsumed,
   728  				Value: analyzeInfo.TimeConsumed,
   729  				Unit:  Statistic_Unit_ns,
   730  			},
   731  			{
   732  				Name:  WaitTime,
   733  				Value: analyzeInfo.WaitTimeConsumed,
   734  				Unit:  Statistic_Unit_ns,
   735  			},
   736  			{
   737  				Name:  ScanTime,
   738  				Value: analyzeInfo.ScanTime,
   739  				Unit:  Statistic_Unit_ns,
   740  			},
   741  			{
   742  				Name:  InsertTime,
   743  				Value: analyzeInfo.InsertTime,
   744  				Unit:  Statistic_Unit_ns,
   745  			},
   746  		}
   747  		mbps := []StatisticValue{
   748  			{
   749  				Name:  InputRows,
   750  				Value: analyzeInfo.InputRows,
   751  				Unit:  Statistic_Unit_count, //"count",
   752  			},
   753  			{
   754  				Name:  OutputRows,
   755  				Value: analyzeInfo.OutputRows,
   756  				Unit:  Statistic_Unit_count, //"count",
   757  			},
   758  			{
   759  				Name:  InputSize,
   760  				Value: analyzeInfo.InputSize,
   761  				Unit:  Statistic_Unit_byte, //"byte",
   762  			},
   763  			{
   764  				Name:  OutputSize,
   765  				Value: analyzeInfo.OutputSize,
   766  				Unit:  Statistic_Unit_byte, //"byte",
   767  			},
   768  		}
   769  
   770  		mems := []StatisticValue{
   771  			{
   772  				Name:  MemorySize,
   773  				Value: analyzeInfo.MemorySize,
   774  				Unit:  Statistic_Unit_byte, //"byte",
   775  			},
   776  		}
   777  
   778  		io := []StatisticValue{
   779  			{
   780  				Name:  DiskIO,
   781  				Value: analyzeInfo.DiskIO,
   782  				Unit:  Statistic_Unit_byte, //"byte",
   783  			},
   784  			{
   785  				Name:  S3IOByte,
   786  				Value: analyzeInfo.S3IOByte,
   787  				Unit:  Statistic_Unit_byte, //"byte",
   788  			},
   789  			{
   790  				Name:  S3IOInputCount,
   791  				Value: analyzeInfo.S3IOInputCount,
   792  				Unit:  Statistic_Unit_count, //"count",
   793  			},
   794  			{
   795  				Name:  S3IOOutputCount,
   796  				Value: analyzeInfo.S3IOOutputCount,
   797  				Unit:  Statistic_Unit_count, //"count",
   798  			},
   799  		}
   800  
   801  		nw := []StatisticValue{
   802  			{
   803  				Name:  Network,
   804  				Value: analyzeInfo.NetworkIO,
   805  				Unit:  Statistic_Unit_byte, //"byte",
   806  			},
   807  		}
   808  
   809  		statistics.Time = append(statistics.Time, times...)
   810  		statistics.Throughput = append(statistics.Throughput, mbps...)
   811  		statistics.Memory = append(statistics.Memory, mems...)
   812  		statistics.IO = append(statistics.IO, io...)
   813  		statistics.Network = append(statistics.Network, nw...)
   814  	}
   815  	return *statistics
   816  }
   817  
   818  func (m MarshalNodeImpl) GetTotalStats() TotalStats {
   819  	totalStats := TotalStats{
   820  		Name: "Time spent",
   821  		Unit: "ns",
   822  	}
   823  	if m.node.AnalyzeInfo != nil {
   824  		totalStats.Value = m.node.AnalyzeInfo.TimeConsumed
   825  	} else {
   826  		totalStats.Value = 0
   827  	}
   828  	return totalStats
   829  }
   830  
   831  var _ MarshalNode = MarshalNodeImpl{}
   832  
   833  func GetExprsLabelValue(ctx context.Context, exprList []*plan.Expr, options *ExplainOptions) ([]string, error) {
   834  	if exprList == nil {
   835  		return make([]string, 0), nil
   836  	}
   837  	result := make([]string, 0, len(exprList))
   838  	buf := bytes.NewBuffer(make([]byte, 0, 200))
   839  	for _, v := range exprList {
   840  		buf.Reset()
   841  		err := describeExpr(ctx, v, options, buf)
   842  		if err != nil {
   843  			return result, err
   844  		}
   845  		result = append(result, buf.String())
   846  	}
   847  	return result, nil
   848  }
   849  
   850  func GetOrderByLabelValue(ctx context.Context, orderbyList []*plan.OrderBySpec, options *ExplainOptions) ([]string, error) {
   851  	if orderbyList == nil {
   852  		return make([]string, 0), nil
   853  	}
   854  	result := make([]string, 0, len(orderbyList))
   855  	buf := bytes.NewBuffer(make([]byte, 0, 200))
   856  	for _, v := range orderbyList {
   857  		buf.Reset()
   858  		err := describeExpr(ctx, v.Expr, options, buf)
   859  		if err != nil {
   860  			return result, err
   861  		}
   862  
   863  		flagKey := int32(v.Flag)
   864  		orderbyFlag := plan.OrderBySpec_OrderByFlag_name[flagKey]
   865  		result = append(result, buf.String()+" "+orderbyFlag)
   866  	}
   867  	return result, nil
   868  }
   869  
   870  func GetDeleteTableLabelValue(deleteCtx *plan.DeleteCtx) []string {
   871  	if deleteCtx == nil {
   872  		return make([]string, 0)
   873  	}
   874  	result := make([]string, 0)
   875  	ref := deleteCtx.Ref
   876  	result = append(result, ref.SchemaName+"."+ref.ObjName)
   877  	return result
   878  }
   879  
   880  func GetTableColsLableValue(ctx context.Context, cols []*plan.ColDef, options *ExplainOptions) []string {
   881  	columns := make([]string, len(cols))
   882  	for i, col := range cols {
   883  		columns[i] = col.Name
   884  	}
   885  	return columns
   886  }