code: func (p *PhysicalWindow) ExplainInfo() string {
  	buffer := bytes.NewBufferString(p.WindowFuncDesc.String())
  	buffer.WriteString(" over(")
  	isFirst := true
  	if len(p.PartitionBy) > 0 {
  		buffer.WriteString("partition by ")
  		for i, item := range p.PartitionBy {
  			fmt.Fprintf(buffer, "%s", item.Col.ExplainInfo())
  			if i+1 < len(p.PartitionBy) {
  				buffer.WriteString(", ")
  			}
  		}
  		isFirst = false
  	}
  	if len(p.OrderBy) > 0 {
  		if !isFirst {
  			buffer.WriteString(" ")
  		}
  		buffer.WriteString("order by ")
  		for i, item := range p.OrderBy {
  			order := "asc"
  			if item.Desc {
  				order = "desc"
  			}
  			fmt.Fprintf(buffer, "%s %s", item.Col.ExplainInfo(), order)
  			if i+1 < len(p.OrderBy) {
  				buffer.WriteString(", ")
  			}
  		}
  		isFirst = false
  	}
  	if p.Frame != nil {
  		if !isFirst {
  			buffer.WriteString(" ")
  		}
  		if p.Frame.Type == ast.Rows {
  			buffer.WriteString("rows")
  		} else {
  			buffer.WriteString("range")
  		}
  		buffer.WriteString(" between ")
  		p.formatFrameBound(buffer, p.Frame.Start)
  		buffer.WriteString(" and ")
  		p.formatFrameBound(buffer, p.Frame.End)
  	}
  	buffer.WriteString(")")
  	return buffer.String()
  }
docs: // ExplainInfo implements PhysicalPlan interface.