code: func (b *PlanBuilder) buildTrace(trace *ast.TraceStmt) (Plan, error) {
  	if _, ok := trace.Stmt.(*ast.SelectStmt); !ok && trace.Format == "row" {
  		return nil, errors.New("trace only supports select query when format is row")
  	}
  
  	p := &Trace{StmtNode: trace.Stmt, Format: trace.Format}
  
  	switch trace.Format {
  	case "row":
  		retFields := []string{"operation", "duration", "spanID"}
  		schema := expression.NewSchema(make([]*expression.Column, 0, len(retFields))...)
  		schema.Append(buildColumn("", "operation", mysql.TypeString, mysql.MaxBlobWidth))
  		schema.Append(buildColumn("", "startTS", mysql.TypeString, mysql.MaxBlobWidth))
  		schema.Append(buildColumn("", "duration", mysql.TypeString, mysql.MaxBlobWidth))
  		p.SetSchema(schema)
  	case "json":
  		retFields := []string{"json"}
  		schema := expression.NewSchema(make([]*expression.Column, 0, len(retFields))...)
  		schema.Append(buildColumn("", "operation", mysql.TypeString, mysql.MaxBlobWidth))
  		p.SetSchema(schema)
  	default:
  		return nil, errors.New("trace format should be one of 'row' or 'json'")
  	}
  	return p, nil
  }
docs: // buildTrace builds a trace plan. Inside this method, it first optimize the
  // underlying query and then constructs a schema, which will be used to constructs
  // rows result.