optgen execexplain test.opt
# Scan returns a node that represents a scan of the given index on
# the given table.
define Scan {
    Table cat.Table
    Index cat.Index
    Params exec.ScanParams
    ReqOrdering exec.OutputOrdering
}

define Filter {
    Input exec.Node
    Filter tree.TypedExpr
    ReqOrdering exec.OutputOrdering
}

define HashJoin {
    JoinType descpb.JoinType
    Left exec.Node
    Right exec.Node
    LeftEqCols []exec.NodeColumnOrdinal
    RightEqCols []exec.NodeColumnOrdinal
    LeftEqColsAreKey bool
    RightEqColsAreKey bool
    ExtraOnCond tree.TypedExpr
}
----
----
// Code generated by optgen; [omitted]

package explain

import (
	"github.com/cockroachdb/cockroach/pkg/sql/catalog/colinfo"
	"github.com/cockroachdb/cockroach/pkg/sql/catalog/descpb"
	"github.com/cockroachdb/cockroach/pkg/sql/inverted"
	"github.com/cockroachdb/cockroach/pkg/sql/opt"
	"github.com/cockroachdb/cockroach/pkg/sql/opt/cat"
	"github.com/cockroachdb/cockroach/pkg/sql/opt/constraint"
	"github.com/cockroachdb/cockroach/pkg/sql/opt/exec"
	"github.com/cockroachdb/cockroach/pkg/sql/sem/tree"
	"github.com/cockroachdb/cockroach/pkg/sql/types"
)

func (f *Factory) ConstructScan(
	table cat.Table,
	index cat.Index,
	params exec.ScanParams,
	reqOrdering exec.OutputOrdering,
) (exec.Node, error) {
	args := &scanArgs{
		Table:       table,
		Index:       index,
		Params:      params,
		ReqOrdering: reqOrdering,
	}
	_n, err := newNode(scanOp, args, reqOrdering)
	if err != nil {
		return nil, err
	}
	// Build the "real" node.
	wrapped, err := f.wrappedFactory.ConstructScan(
		table,
		index,
		params,
		reqOrdering,
	)
	if err != nil {
		return nil, err
	}
	_n.wrappedNode = wrapped
	return _n, nil
}

func (f *Factory) ConstructFilter(
	input exec.Node,
	filter tree.TypedExpr,
	reqOrdering exec.OutputOrdering,
) (exec.Node, error) {
	inputNode := input.(*Node)
	args := &filterArgs{
		Input:       inputNode,
		Filter:      filter,
		ReqOrdering: reqOrdering,
	}
	_n, err := newNode(filterOp, args, reqOrdering, inputNode)
	if err != nil {
		return nil, err
	}
	// Build the "real" node.
	wrapped, err := f.wrappedFactory.ConstructFilter(
		inputNode.WrappedNode(),
		filter,
		reqOrdering,
	)
	if err != nil {
		return nil, err
	}
	_n.wrappedNode = wrapped
	return _n, nil
}

func (f *Factory) ConstructHashJoin(
	joinType descpb.JoinType,
	left exec.Node,
	right exec.Node,
	leftEqCols []exec.NodeColumnOrdinal,
	rightEqCols []exec.NodeColumnOrdinal,
	leftEqColsAreKey bool,
	rightEqColsAreKey bool,
	extraOnCond tree.TypedExpr,
) (exec.Node, error) {
	leftNode := left.(*Node)
	rightNode := right.(*Node)
	args := &hashJoinArgs{
		JoinType:          joinType,
		Left:              leftNode,
		Right:             rightNode,
		LeftEqCols:        leftEqCols,
		RightEqCols:       rightEqCols,
		LeftEqColsAreKey:  leftEqColsAreKey,
		RightEqColsAreKey: rightEqColsAreKey,
		ExtraOnCond:       extraOnCond,
	}
	_n, err := newNode(hashJoinOp, args, nil /* ordering */, leftNode, rightNode)
	if err != nil {
		return nil, err
	}
	// Build the "real" node.
	wrapped, err := f.wrappedFactory.ConstructHashJoin(
		joinType,
		leftNode.WrappedNode(),
		rightNode.WrappedNode(),
		leftEqCols,
		rightEqCols,
		leftEqColsAreKey,
		rightEqColsAreKey,
		extraOnCond,
	)
	if err != nil {
		return nil, err
	}
	_n.wrappedNode = wrapped
	return _n, nil
}

type execOperator int

const (
	unknownOp execOperator = iota
	scanOp
	filterOp
	hashJoinOp
	numOperators
)

type scanArgs struct {
	Table       cat.Table
	Index       cat.Index
	Params      exec.ScanParams
	ReqOrdering exec.OutputOrdering
}

type filterArgs struct {
	Input       *Node
	Filter      tree.TypedExpr
	ReqOrdering exec.OutputOrdering
}

type hashJoinArgs struct {
	JoinType          descpb.JoinType
	Left              *Node
	Right             *Node
	LeftEqCols        []exec.NodeColumnOrdinal
	RightEqCols       []exec.NodeColumnOrdinal
	LeftEqColsAreKey  bool
	RightEqColsAreKey bool
	ExtraOnCond       tree.TypedExpr
}
----
----
