github.com/matrixorigin/matrixone@v0.7.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  	"context"
    19  	"strconv"
    20  	"strings"
    21  
    22  	"github.com/matrixorigin/matrixone/pkg/common/moerr"
    23  	"github.com/matrixorigin/matrixone/pkg/pb/plan"
    24  )
    25  
    26  func ConvertNode(ctx context.Context, node *plan.Node, options *ExplainOptions) (*Node, error) {
    27  	marshalNodeImpl := NewMarshalNodeImpl(node)
    28  	newNode := &Node{
    29  		NodeId:     strconv.FormatInt(int64(node.NodeId), 10),
    30  		Statistics: marshalNodeImpl.GetStatistics(ctx, options),
    31  		Stats:      marshalNodeImpl.GetStats(),
    32  		TotalStats: marshalNodeImpl.GetTotalStats(),
    33  	}
    34  	name, err := marshalNodeImpl.GetNodeName(ctx)
    35  	if err != nil {
    36  		return nil, err
    37  	}
    38  	newNode.Name = name
    39  
    40  	title, err := marshalNodeImpl.GetNodeTitle(ctx, options)
    41  	if err != nil {
    42  		return nil, err
    43  	}
    44  	newNode.Title = title
    45  
    46  	labels, err := marshalNodeImpl.GetNodeLabels(ctx, options)
    47  	if err != nil {
    48  		return nil, err
    49  	}
    50  	newNode.Labels = labels
    51  	return newNode, nil
    52  }
    53  
    54  type MarshalNode interface {
    55  	GetNodeName(ctx context.Context) (string, error)
    56  	GetNodeTitle(ctx context.Context, options *ExplainOptions) (string, error)
    57  	GetNodeLabels(ctx context.Context, options *ExplainOptions) ([]Label, error)
    58  	GetStatistics(ctx context.Context, options *ExplainOptions) Statistics
    59  	GetStats() Stats
    60  	GetTotalStats() TotalStats
    61  }
    62  
    63  type MarshalNodeImpl struct {
    64  	node *plan.Node
    65  }
    66  
    67  func NewMarshalNodeImpl(node *plan.Node) *MarshalNodeImpl {
    68  	return &MarshalNodeImpl{
    69  		node: node,
    70  	}
    71  }
    72  
    73  func (m MarshalNodeImpl) GetStats() Stats {
    74  	if m.node.Stats != nil {
    75  		return Stats{
    76  			BlockNum:    m.node.Stats.BlockNum,
    77  			Cost:        m.node.Stats.Cost,
    78  			Outcnt:      m.node.Stats.Outcnt,
    79  			HashmapSize: m.node.Stats.HashmapSize,
    80  			Rowsize:     m.node.Stats.Rowsize,
    81  		}
    82  	} else {
    83  		return Stats{}
    84  	}
    85  }
    86  
    87  func (m MarshalNodeImpl) GetNodeName(ctx context.Context) (string, error) {
    88  	var name string
    89  	// Get the Node Name
    90  	switch m.node.NodeType {
    91  	case plan.Node_UNKNOWN:
    92  		name = "UnKnow Node"
    93  	case plan.Node_VALUE_SCAN:
    94  		name = "Values Scan"
    95  	case plan.Node_TABLE_SCAN:
    96  		name = "Table Scan"
    97  	case plan.Node_FUNCTION_SCAN:
    98  		name = "Function Scan"
    99  	case plan.Node_EXTERNAL_SCAN:
   100  		name = "External Scan"
   101  	case plan.Node_MATERIAL_SCAN:
   102  		name = "Material Scan"
   103  	case plan.Node_PROJECT:
   104  		name = "Project"
   105  	case plan.Node_EXTERNAL_FUNCTION:
   106  		name = "External Function"
   107  	case plan.Node_MATERIAL:
   108  		name = "Material"
   109  	case plan.Node_RECURSIVE_CTE:
   110  		name = "Recursive CTE"
   111  	case plan.Node_SINK:
   112  		name = "Sink"
   113  	case plan.Node_SINK_SCAN:
   114  		name = "Sink Scan"
   115  	case plan.Node_AGG:
   116  		name = "Aggregate"
   117  	case plan.Node_DISTINCT:
   118  		name = "Distinct"
   119  	case plan.Node_FILTER:
   120  		name = "Filter"
   121  	case plan.Node_JOIN:
   122  		name = "Join"
   123  	case plan.Node_SAMPLE:
   124  		name = "Sample"
   125  	case plan.Node_SORT:
   126  		name = "Sort"
   127  	case plan.Node_UNION:
   128  		name = "Union"
   129  	case plan.Node_UNION_ALL:
   130  		name = "Union All"
   131  	case plan.Node_UNIQUE:
   132  		name = "Unique"
   133  	case plan.Node_WINDOW:
   134  		name = "Window"
   135  	case plan.Node_BROADCAST:
   136  		name = "Broadcast"
   137  	case plan.Node_SPLIT:
   138  		name = "Split"
   139  	case plan.Node_GATHER:
   140  		name = "Gather"
   141  	case plan.Node_ASSERT:
   142  		name = "Assert"
   143  	case plan.Node_INSERT:
   144  		name = "Insert"
   145  	case plan.Node_UPDATE:
   146  		name = "Update"
   147  	case plan.Node_DELETE:
   148  		name = "Delete"
   149  	case plan.Node_INTERSECT:
   150  		name = "Intersect"
   151  	case plan.Node_INTERSECT_ALL:
   152  		name = "Intersect All"
   153  	case plan.Node_MINUS:
   154  		name = "Minus"
   155  	case plan.Node_MINUS_ALL:
   156  		name = "Minus All"
   157  	default:
   158  		return name, moerr.NewInternalError(ctx, "Unsupported node type when plan is serialized to json")
   159  	}
   160  	return name, nil
   161  }
   162  
   163  func (m MarshalNodeImpl) GetNodeTitle(ctx context.Context, options *ExplainOptions) (string, error) {
   164  	var result string
   165  	var err error
   166  	switch m.node.NodeType {
   167  	case plan.Node_TABLE_SCAN, plan.Node_EXTERNAL_SCAN, plan.Node_MATERIAL_SCAN, plan.Node_INSERT:
   168  		//"title" : "SNOWFLAKE_SAMPLE_DATA.TPCDS_SF10TCL.DATE_DIM",
   169  		if m.node.ObjRef != nil {
   170  			result += m.node.ObjRef.GetSchemaName() + "." + m.node.ObjRef.GetObjName()
   171  		} else if m.node.TableDef != nil {
   172  			result += m.node.TableDef.GetName()
   173  		} else {
   174  			return result, moerr.NewInvalidInput(ctx, "Table definition not found when plan is serialized to json")
   175  		}
   176  	case plan.Node_UPDATE:
   177  		if m.node.UpdateCtx != nil {
   178  			first := true
   179  			for _, ctx := range m.node.UpdateCtx.Ref {
   180  				if !first {
   181  					result += ", "
   182  				}
   183  				result += ctx.SchemaName + "." + ctx.ObjName
   184  				if first {
   185  					first = false
   186  				}
   187  			}
   188  		} else {
   189  			return result, moerr.NewInvalidInput(ctx, "Table definition not found when plan is serialized to json")
   190  		}
   191  	case plan.Node_DELETE:
   192  		if m.node.DeleteCtx != nil {
   193  			first := true
   194  			for _, ctx := range m.node.DeleteCtx.Ref {
   195  				if !first {
   196  					result += ", "
   197  				}
   198  				result += ctx.SchemaName + "." + ctx.ObjName
   199  				if first {
   200  					first = false
   201  				}
   202  			}
   203  		} else {
   204  			return result, moerr.NewInternalError(ctx, "Table definition not found when plan is serialized to json")
   205  		}
   206  	case plan.Node_PROJECT, plan.Node_VALUE_SCAN, plan.Node_UNION, plan.Node_UNION_ALL,
   207  		plan.Node_INTERSECT, plan.Node_INTERSECT_ALL, plan.Node_MINUS:
   208  		//"title" : "STORE.S_STORE_NAME,STORE.S_STORE_ID,WSS.D_WEEK_SEQ"
   209  		exprs := NewExprListDescribeImpl(m.node.ProjectList)
   210  		result, err = exprs.GetDescription(ctx, options)
   211  		if err != nil {
   212  			return result, err
   213  		}
   214  	case plan.Node_AGG:
   215  		// "SUM(IFF(DATE_DIM.D_DAY_NAME = 'Sunday', STORE_SALES.SS_SALES_PRICE, null))"
   216  		exprs := NewExprListDescribeImpl(m.node.AggList)
   217  		result, err = exprs.GetDescription(ctx, options)
   218  		if err != nil {
   219  			return result, err
   220  		}
   221  	case plan.Node_FILTER:
   222  		//"title" : "(D_0.D_MONTH_SEQ >= 1189) AND (D_0.D_MONTH_SEQ <= 1200)",
   223  		exprs := NewExprListDescribeImpl(m.node.FilterList)
   224  		result, err = exprs.GetDescription(ctx, options)
   225  		if err != nil {
   226  			return result, err
   227  		}
   228  	case plan.Node_JOIN:
   229  		//"title" : "(DATE_DIM.D_DATE_SK = STORE_SALES.SS_SOLD_DATE_SK)",
   230  		exprs := NewExprListDescribeImpl(m.node.OnList)
   231  		result, err = exprs.GetDescription(ctx, options)
   232  		if err != nil {
   233  			return result, err
   234  		}
   235  	case plan.Node_SORT:
   236  		//"title" : "STORE.S_STORE_NAME ASC NULLS LAST,STORE.S_STORE_ID ASC NULLS LAST,WSS.D_WEEK_SEQ ASC NULLS LAST",
   237  		orderByDescImpl := NewOrderByDescribeImpl(m.node.OrderBy)
   238  		result, err = orderByDescImpl.GetDescription(ctx, options)
   239  		if err != nil {
   240  			return result, err
   241  		}
   242  	default:
   243  		return "", moerr.NewInternalError(ctx, "Unsupported node type when plan is serialized to json")
   244  	}
   245  	return strings.TrimSpace(result), nil
   246  }
   247  
   248  func (m MarshalNodeImpl) GetNodeLabels(ctx context.Context, options *ExplainOptions) ([]Label, error) {
   249  	labels := make([]Label, 0)
   250  
   251  	switch m.node.NodeType {
   252  	case plan.Node_TABLE_SCAN, plan.Node_FUNCTION_SCAN, plan.Node_EXTERNAL_SCAN,
   253  		plan.Node_MATERIAL_SCAN:
   254  		tableDef := m.node.TableDef
   255  		objRef := m.node.ObjRef
   256  		var fullTableName string
   257  		if objRef != nil {
   258  			fullTableName += objRef.GetSchemaName() + "." + objRef.GetObjName()
   259  		} else if tableDef != nil {
   260  			fullTableName += tableDef.GetName()
   261  		} else {
   262  			return nil, moerr.NewInternalError(ctx, "Table definition not found when plan is serialized to json")
   263  		}
   264  
   265  		labels = append(labels, Label{
   266  			Name:  "Full table name",
   267  			Value: fullTableName,
   268  		})
   269  
   270  		// "name" : "Columns (2 / 28)",
   271  		columns := GetTableColsLableValue(ctx, tableDef.Cols, options)
   272  
   273  		labels = append(labels, Label{
   274  			Name:  "Columns",
   275  			Value: columns,
   276  		})
   277  
   278  		labels = append(labels, Label{
   279  			Name:  "Total columns",
   280  			Value: len(tableDef.Name2ColIndex),
   281  		})
   282  
   283  		labels = append(labels, Label{
   284  			Name:  "Scan columns",
   285  			Value: len(tableDef.Cols),
   286  		})
   287  
   288  	case plan.Node_INSERT:
   289  		tableDef := m.node.TableDef
   290  		objRef := m.node.ObjRef
   291  		var fullTableName string
   292  		if objRef != nil {
   293  			fullTableName += objRef.GetSchemaName() + "." + objRef.GetObjName()
   294  		} else if tableDef != nil {
   295  			fullTableName += tableDef.GetName()
   296  		} else {
   297  			return nil, moerr.NewInternalError(ctx, "Table definition not found when plan is serialized to json")
   298  		}
   299  
   300  		labels = append(labels, Label{
   301  			Name:  "Full table name",
   302  			Value: fullTableName,
   303  		})
   304  
   305  		// "name" : "Columns (2 / 28)",
   306  		columns := GetTableColsLableValue(ctx, tableDef.Cols, options)
   307  
   308  		labels = append(labels, Label{
   309  			Name:  "Columns",
   310  			Value: columns,
   311  		})
   312  
   313  		labels = append(labels, Label{
   314  			Name:  "Total columns",
   315  			Value: len(tableDef.Cols),
   316  		})
   317  
   318  		labels = append(labels, Label{
   319  			Name:  "Scan columns",
   320  			Value: len(tableDef.Cols),
   321  		})
   322  	case plan.Node_UPDATE:
   323  		if m.node.UpdateCtx != nil {
   324  			updateTableNames := GetUpdateTableLableValue(ctx, m.node.UpdateCtx, options)
   325  			labels = append(labels, Label{
   326  				Name:  "Full table name",
   327  				Value: updateTableNames,
   328  			})
   329  
   330  			updateCols := make([]string, 0)
   331  			for i, ctx := range m.node.UpdateCtx.Ref {
   332  				if m.node.UpdateCtx.UpdateCol[i] != nil {
   333  					upcols := GetUpdateTableColsLableValue(m.node.UpdateCtx.UpdateCol[i].Map, ctx.SchemaName, ctx.ObjName, options)
   334  					updateCols = append(updateCols, upcols...)
   335  				}
   336  			}
   337  			labels = append(labels, Label{
   338  				Name:  "Update columns",
   339  				Value: updateCols,
   340  			})
   341  		} else {
   342  			return nil, moerr.NewInvalidInput(ctx, "Table definition not found when plan is serialized to json")
   343  		}
   344  	case plan.Node_DELETE:
   345  		if m.node.DeleteCtx != nil {
   346  			deleteTableNames := GetDeleteTableLableValue(ctx, m.node.DeleteCtx, options)
   347  			labels = append(labels, Label{
   348  				Name:  "Full table name",
   349  				Value: deleteTableNames,
   350  			})
   351  		} else {
   352  			return nil, moerr.NewInvalidInput(ctx, "Table definition not found when plan is serialized to json")
   353  		}
   354  	case plan.Node_PROJECT:
   355  		value, err := GetExprsLabelValue(ctx, m.node.ProjectList, options)
   356  		if err != nil {
   357  			return nil, err
   358  		}
   359  		labels = append(labels, Label{
   360  			Name:  "List of expressions",
   361  			Value: value,
   362  		})
   363  	case plan.Node_AGG:
   364  		// Get Group key info
   365  		if len(m.node.GroupBy) > 0 {
   366  			// Get Grouping Key
   367  			value, err := GetExprsLabelValue(ctx, m.node.GroupBy, options)
   368  			if err != nil {
   369  				return nil, err
   370  			}
   371  			labels = append(labels, Label{
   372  				Name:  "Grouping keys",
   373  				Value: value,
   374  			})
   375  		}
   376  
   377  		// Get Aggregate function info
   378  		if len(m.node.AggList) > 0 {
   379  			value, err := GetExprsLabelValue(ctx, m.node.AggList, options)
   380  			if err != nil {
   381  				return nil, err
   382  			}
   383  			labels = append(labels, Label{
   384  				Name:  "Aggregate functions",
   385  				Value: value,
   386  			})
   387  		}
   388  	case plan.Node_FILTER:
   389  		value, err := GetExprsLabelValue(ctx, m.node.FilterList, options)
   390  		if err != nil {
   391  			return nil, err
   392  		}
   393  		labels = append(labels, Label{
   394  			Name:  "Filter conditions",
   395  			Value: value,
   396  		})
   397  	case plan.Node_JOIN:
   398  		// Get Join type
   399  		labels = append(labels, Label{
   400  			Name:  "Join type",
   401  			Value: m.node.JoinType.String(),
   402  		})
   403  
   404  		// Get Join Condition info
   405  		if len(m.node.OnList) > 0 {
   406  			value, err := GetExprsLabelValue(ctx, m.node.OnList, options)
   407  			if err != nil {
   408  				return nil, err
   409  			}
   410  			labels = append(labels, Label{
   411  				Name:  "Join conditions",
   412  				Value: value,
   413  			})
   414  		}
   415  		labels = append(labels, Label{
   416  			Name:  "Left node id",
   417  			Value: m.node.Children[0],
   418  		})
   419  		labels = append(labels, Label{
   420  			Name:  "Right node id",
   421  			Value: m.node.Children[1],
   422  		})
   423  	case plan.Node_SORT:
   424  		result, err := GettOrderByLabelValue(ctx, m.node.OrderBy, options)
   425  		if err != nil {
   426  			return nil, err
   427  		}
   428  		labels = append(labels, Label{
   429  			Name:  "Sort keys",
   430  			Value: result,
   431  		})
   432  	case plan.Node_VALUE_SCAN:
   433  		value, err := GetExprsLabelValue(ctx, m.node.ProjectList, options)
   434  		if err != nil {
   435  			return nil, err
   436  		}
   437  		labels = append(labels, Label{
   438  			Name:  "List of values",
   439  			Value: value,
   440  		})
   441  	case plan.Node_UNION:
   442  		value, err := GetExprsLabelValue(ctx, m.node.ProjectList, options)
   443  		if err != nil {
   444  			return nil, err
   445  		}
   446  		labels = append(labels, Label{
   447  			Name:  "Union expressions",
   448  			Value: value,
   449  		})
   450  	case plan.Node_UNION_ALL:
   451  		value, err := GetExprsLabelValue(ctx, m.node.ProjectList, options)
   452  		if err != nil {
   453  			return nil, err
   454  		}
   455  		labels = append(labels, Label{
   456  			Name:  "Union all expressions",
   457  			Value: value,
   458  		})
   459  	case plan.Node_INTERSECT:
   460  		value, err := GetExprsLabelValue(ctx, m.node.ProjectList, options)
   461  		if err != nil {
   462  			return nil, err
   463  		}
   464  		labels = append(labels, Label{
   465  			Name:  "Intersect expressions",
   466  			Value: value,
   467  		})
   468  	case plan.Node_INTERSECT_ALL:
   469  		value, err := GetExprsLabelValue(ctx, m.node.ProjectList, options)
   470  		if err != nil {
   471  			return nil, err
   472  		}
   473  		labels = append(labels, Label{
   474  			Name:  "Intersect All expressions",
   475  			Value: value,
   476  		})
   477  	case plan.Node_MINUS:
   478  		value, err := GetExprsLabelValue(ctx, m.node.ProjectList, options)
   479  		if err != nil {
   480  			return nil, err
   481  		}
   482  		labels = append(labels, Label{
   483  			Name:  "Minus expressions",
   484  			Value: value,
   485  		})
   486  	default:
   487  		return nil, moerr.NewInternalError(ctx, "Unsupported node type when plan is serialized to json")
   488  	}
   489  
   490  	if m.node.NodeType != plan.Node_FILTER && m.node.FilterList != nil {
   491  		// Where condition
   492  		value, err := GetExprsLabelValue(ctx, m.node.FilterList, options)
   493  		if err != nil {
   494  			return nil, err
   495  		}
   496  		labels = append(labels, Label{
   497  			Name:  "Filter conditions",
   498  			Value: value,
   499  		})
   500  	}
   501  
   502  	// Get Limit And Offset info
   503  	if m.node.Limit != nil {
   504  		limitInfo, err := describeExpr(ctx, m.node.Limit, options)
   505  		if err != nil {
   506  			return nil, err
   507  		}
   508  		labels = append(labels, Label{
   509  			Name:  "Number of rows",
   510  			Value: limitInfo,
   511  		})
   512  
   513  		if m.node.Offset != nil {
   514  			offsetInfo, err := describeExpr(ctx, m.node.Offset, options)
   515  			if err != nil {
   516  				return nil, err
   517  			}
   518  			labels = append(labels, Label{
   519  				Name:  "Offset",
   520  				Value: offsetInfo,
   521  			})
   522  		} else {
   523  			labels = append(labels, Label{
   524  				Name:  "Offset",
   525  				Value: 0,
   526  			})
   527  		}
   528  	}
   529  	return labels, nil
   530  }
   531  
   532  const TimeConsumed = "Time Consumed"
   533  const WaitTime = "Wait Time"
   534  
   535  const InputRows = "Input Rows"
   536  const OutputRows = "Output Rows"
   537  const InputSize = "Input Size"
   538  const OutputSize = "Output Size"
   539  const MemorySize = "Memory Size"
   540  const DiskIO = "Disk IO"
   541  const S3IOByte = "S3 IO Byte"
   542  const S3IOCount = "S3 IO Count"
   543  const Network = "Network"
   544  
   545  func (m MarshalNodeImpl) GetStatistics(ctx context.Context, options *ExplainOptions) Statistics {
   546  	statistics := NewStatistics()
   547  	if options.Analyze && m.node.AnalyzeInfo != nil {
   548  		analyzeInfo := m.node.AnalyzeInfo
   549  		times := []StatisticValue{
   550  			{
   551  				Name:  TimeConsumed,
   552  				Value: analyzeInfo.TimeConsumed,
   553  				Unit:  "ns",
   554  			},
   555  			{
   556  				Name:  WaitTime,
   557  				Value: analyzeInfo.WaitTimeConsumed,
   558  				Unit:  "ns",
   559  			},
   560  		}
   561  		mbps := []StatisticValue{
   562  			{
   563  				Name:  InputRows,
   564  				Value: analyzeInfo.InputRows,
   565  				Unit:  "count",
   566  			},
   567  			{
   568  				Name:  OutputRows,
   569  				Value: analyzeInfo.OutputRows,
   570  				Unit:  "count",
   571  			},
   572  			{
   573  				Name:  InputSize,
   574  				Value: analyzeInfo.InputSize,
   575  				Unit:  "byte",
   576  			},
   577  			{
   578  				Name:  OutputSize,
   579  				Value: analyzeInfo.OutputSize,
   580  				Unit:  "byte",
   581  			},
   582  		}
   583  
   584  		mems := []StatisticValue{
   585  			{
   586  				Name:  MemorySize,
   587  				Value: analyzeInfo.MemorySize,
   588  				Unit:  "byte",
   589  			},
   590  		}
   591  
   592  		io := []StatisticValue{
   593  			{
   594  				Name:  DiskIO,
   595  				Value: analyzeInfo.DiskIO,
   596  				Unit:  "byte",
   597  			},
   598  			{
   599  				Name:  S3IOByte,
   600  				Value: analyzeInfo.S3IOByte,
   601  				Unit:  "byte",
   602  			},
   603  			{
   604  				Name:  S3IOCount,
   605  				Value: analyzeInfo.S3IOCount,
   606  				Unit:  "count",
   607  			},
   608  		}
   609  
   610  		nw := []StatisticValue{
   611  			{
   612  				Name:  Network,
   613  				Value: analyzeInfo.NetworkIO,
   614  				Unit:  "byte",
   615  			},
   616  		}
   617  
   618  		statistics.Time = append(statistics.Time, times...)
   619  		statistics.Throughput = append(statistics.Throughput, mbps...)
   620  		statistics.Memory = append(statistics.Memory, mems...)
   621  		statistics.IO = append(statistics.IO, io...)
   622  		statistics.Network = append(statistics.Network, nw...)
   623  	}
   624  	return *statistics
   625  }
   626  
   627  func (m MarshalNodeImpl) GetTotalStats() TotalStats {
   628  	totalStats := TotalStats{
   629  		Name: "Time spent",
   630  		Unit: "us",
   631  	}
   632  	if m.node.AnalyzeInfo != nil {
   633  		totalStats.Value = m.node.AnalyzeInfo.TimeConsumed
   634  	} else {
   635  		totalStats.Value = 0
   636  	}
   637  	return totalStats
   638  }
   639  
   640  var _ MarshalNode = MarshalNodeImpl{}
   641  
   642  func GetExprsLabelValue(ctx context.Context, exprList []*plan.Expr, options *ExplainOptions) ([]string, error) {
   643  	if exprList == nil {
   644  		return make([]string, 0), nil
   645  	}
   646  	result := make([]string, 0)
   647  	for _, v := range exprList {
   648  		descV, err := describeExpr(ctx, v, options)
   649  		if err != nil {
   650  			return result, err
   651  		}
   652  		result = append(result, descV)
   653  	}
   654  	return result, nil
   655  }
   656  
   657  func GettOrderByLabelValue(ctx context.Context, orderbyList []*plan.OrderBySpec, options *ExplainOptions) ([]string, error) {
   658  	if orderbyList == nil {
   659  		return make([]string, 0), nil
   660  	}
   661  	result := make([]string, 0)
   662  	for _, v := range orderbyList {
   663  		descExpr, err := describeExpr(ctx, v.Expr, options)
   664  		if err != nil {
   665  			return result, err
   666  		}
   667  
   668  		flagKey := int32(v.Flag)
   669  		orderbyFlag := plan.OrderBySpec_OrderByFlag_name[flagKey]
   670  		result = append(result, descExpr+" "+orderbyFlag)
   671  	}
   672  	return result, nil
   673  }
   674  
   675  func GetDeleteTableLableValue(ctx context.Context, deleteCtx *plan.DeleteCtx, options *ExplainOptions) []string {
   676  	if deleteCtx == nil {
   677  		return make([]string, 0)
   678  	}
   679  	result := make([]string, 0)
   680  	for _, ctx := range deleteCtx.Ref {
   681  		result = append(result, ctx.SchemaName+"."+ctx.ObjName)
   682  	}
   683  	return result
   684  }
   685  
   686  func GetUpdateTableLableValue(ctx context.Context, updateCtx *plan.UpdateCtx, options *ExplainOptions) []string {
   687  	if updateCtx == nil {
   688  		return make([]string, 0)
   689  	}
   690  	result := make([]string, 0)
   691  	for _, ctx := range updateCtx.Ref {
   692  		result = append(result, ctx.SchemaName+"."+ctx.ObjName)
   693  	}
   694  	return result
   695  }
   696  
   697  func GetTableColsLableValue(ctx context.Context, cols []*plan.ColDef, options *ExplainOptions) []string {
   698  	columns := make([]string, len(cols))
   699  	for i, col := range cols {
   700  		columns[i] = col.Name
   701  	}
   702  	return columns
   703  }
   704  
   705  func GetUpdateTableColsLableValue(cols map[string]int32, db string, tname string, options *ExplainOptions) []string {
   706  	columns := make([]string, len(cols))
   707  	i := 0
   708  	for col := range cols {
   709  		columns[i] = db + "." + tname + "." + col
   710  		i++
   711  	}
   712  	return columns
   713  }