mirror of
https://github.com/featurebasedb/featurebase.git
synced 2026-11-01 15:22:29 +00:00
385 lines
11 KiB
Go
385 lines
11 KiB
Go
package planner
|
|
|
|
import (
|
|
"github.com/featurebasedb/featurebase/v3/sql3/planner/types"
|
|
)
|
|
|
|
// PlanVisitor visits nodes in the plan.
|
|
type PlanVisitor interface {
|
|
// VisitOperator method is invoked for each node during PlanWalk. If the
|
|
// resulting PlanVisitor is not nil, PlanWalk visits each of the children of
|
|
// the node with that visitor, followed by a call of VisitOperator(nil) to
|
|
// the returned visitor.
|
|
VisitOperator(op types.PlanOperator) PlanVisitor
|
|
}
|
|
|
|
// PlanWalk traverses the plan depth-first. It starts by calling
|
|
// v.VisitOperator; node must not be nil. If the result returned by
|
|
// v.VisitOperator is not nil, PlanWalk is invoked recursively with the returned
|
|
// result for each of the children of the plan operator, followed by a call of
|
|
// v.VisitOperator(nil) to the returned result. If v.VisitOperator(op) returns
|
|
// non-nil, then all children are walked, even if one of them returns nil.
|
|
func PlanWalk(v PlanVisitor, op types.PlanOperator) {
|
|
if v = v.VisitOperator(op); v == nil {
|
|
return
|
|
}
|
|
|
|
for _, child := range op.Children() {
|
|
PlanWalk(v, child)
|
|
}
|
|
|
|
v.VisitOperator(nil)
|
|
}
|
|
|
|
type planInspector func(types.PlanOperator) bool
|
|
|
|
func (f planInspector) VisitOperator(op types.PlanOperator) PlanVisitor {
|
|
if f(op) {
|
|
return f
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// InspectPlan traverses the plan op graph depth-first order
|
|
// if f(op) returns true, InspectPlan invokes f recursively for each of the children of op,
|
|
// followed by a call of f(nil).
|
|
func InspectPlan(op types.PlanOperator, f planInspector) {
|
|
PlanWalk(f, op)
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
// ExprVisitor visits expressions in an expression tree.
|
|
type ExprVisitor interface {
|
|
// VisitExpr method is invoked for each expr encountered by ExprWalk.
|
|
// If the result is not nil, ExprWalk visits each of the children
|
|
// of the expr, followed by a call of VisitExpr(nil) to the returned result.
|
|
VisitExpr(expr types.PlanExpression) ExprVisitor
|
|
}
|
|
|
|
func ExprWalk(v ExprVisitor, expr types.PlanExpression) {
|
|
if v = v.VisitExpr(expr); v == nil {
|
|
return
|
|
}
|
|
|
|
for _, child := range expr.Children() {
|
|
ExprWalk(v, child)
|
|
}
|
|
|
|
v.VisitExpr(nil)
|
|
}
|
|
|
|
type exprInspector func(types.PlanExpression) bool
|
|
|
|
func (f exprInspector) VisitExpr(e types.PlanExpression) ExprVisitor {
|
|
if f(e) {
|
|
return f
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// WalkExpressions traverses the plan and calls sql.Walk on any expression it finds.
|
|
func WalkExpressions(v ExprVisitor, node types.PlanOperator) {
|
|
InspectPlan(node, func(node types.PlanOperator) bool {
|
|
if n, ok := node.(types.ContainsExpressions); ok {
|
|
for _, e := range n.Expressions() {
|
|
ExprWalk(v, e)
|
|
}
|
|
}
|
|
return true
|
|
})
|
|
}
|
|
|
|
// InspectExpressions traverses the plan and calls WalkExpressions on any
|
|
// expression it finds.
|
|
func InspectExpressions(node types.PlanOperator, f exprInspector) {
|
|
WalkExpressions(f, node)
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
// PlanOpExprVisitor visits expressions in an expression tree. Like ExprVisitor, but with the added context of the plan op in which
|
|
// an expression is embedded.
|
|
type PlanOpExprVisitor interface {
|
|
// VisitPlanOpExpr method is invoked for each expr encountered by Walk. If the result Visitor is not nil, Walk visits each of
|
|
// the children of the expr with that visitor, followed by a call of VisitPlanOpExpr(nil, nil) to the returned visitor.
|
|
VisitPlanOpExpr(node types.PlanOperator, expression types.PlanExpression) PlanOpExprVisitor
|
|
}
|
|
|
|
// ExprWithPlanOpWalk traverses the expression tree in depth-first order. It starts by calling v.VisitPlanOpExpr(op, expr); expr must
|
|
// not be nil. If the visitor returned by v.VisitPlanOpExpr(op, expr) is not nil, Walk is invoked recursively with the returned
|
|
// visitor for each children of the expr, followed by a call of v.VisitPlanOpExpr(nil, nil) to the returned visitor.
|
|
func ExprWithPlanOpWalk(v PlanOpExprVisitor, n types.PlanOperator, expr types.PlanExpression) {
|
|
if v = v.VisitPlanOpExpr(n, expr); v == nil {
|
|
return
|
|
}
|
|
|
|
for _, child := range expr.Children() {
|
|
ExprWithPlanOpWalk(v, n, child)
|
|
}
|
|
|
|
v.VisitPlanOpExpr(nil, nil)
|
|
}
|
|
|
|
type exprWithNodeInspector func(types.PlanOperator, types.PlanExpression) bool
|
|
|
|
func (f exprWithNodeInspector) VisitPlanOpExpr(n types.PlanOperator, e types.PlanExpression) PlanOpExprVisitor {
|
|
if f(n, e) {
|
|
return f
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// WalkExpressionsWithPlanOp traverses the plan and calls ExprWithPlanOpWalk on any expression it finds.
|
|
func WalkExpressionsWithPlanOp(v PlanOpExprVisitor, n types.PlanOperator) {
|
|
InspectPlan(n, func(n types.PlanOperator) bool {
|
|
if expressioner, ok := n.(types.ContainsExpressions); ok {
|
|
for _, e := range expressioner.Expressions() {
|
|
ExprWithPlanOpWalk(v, n, e)
|
|
}
|
|
}
|
|
return true
|
|
})
|
|
}
|
|
|
|
// InspectExpressionsWithPlanOp traverses the plan and calls f on any expression it finds.
|
|
func InspectExpressionsWithPlanOp(node types.PlanOperator, f exprWithNodeInspector) {
|
|
WalkExpressionsWithPlanOp(f, node)
|
|
}
|
|
|
|
// PlanOpFunc is a function that given a plan op will return either a transformed plan op or the original plan op.
|
|
// If there was a transformation, the bool will be true, and an error if there was an error
|
|
type PlanOpFunc func(n types.PlanOperator) (types.PlanOperator, bool, error)
|
|
|
|
// TransformPlanOp applies a transformation function to the given plan op graph
|
|
func TransformPlanOp(op types.PlanOperator, f PlanOpFunc) (types.PlanOperator, bool, error) {
|
|
|
|
children := op.Children()
|
|
if len(children) == 0 {
|
|
return f(op)
|
|
}
|
|
|
|
var (
|
|
newChildren []types.PlanOperator
|
|
)
|
|
|
|
for i := range children {
|
|
child := children[i]
|
|
child, same, err := TransformPlanOp(child, f)
|
|
if err != nil {
|
|
return nil, true, err
|
|
}
|
|
if !same {
|
|
if newChildren == nil {
|
|
newChildren = make([]types.PlanOperator, len(children))
|
|
copy(newChildren, children)
|
|
}
|
|
newChildren[i] = child
|
|
}
|
|
}
|
|
|
|
var err error
|
|
sameC := true
|
|
if len(newChildren) > 0 {
|
|
sameC = false
|
|
op, err = op.WithChildren(newChildren...)
|
|
if err != nil {
|
|
return nil, true, err
|
|
}
|
|
}
|
|
|
|
op, sameN, err := f(op)
|
|
if err != nil {
|
|
return nil, true, err
|
|
}
|
|
return op, sameC && sameN, nil
|
|
}
|
|
|
|
// ExprWithPlanOpFunc is a function that given an expression and the node
|
|
// that contains it, will return that expression as is or transformed
|
|
// along with an error, if any.
|
|
type ExprWithPlanOpFunc func(types.PlanOperator, types.PlanExpression) (types.PlanExpression, bool, error)
|
|
|
|
// ExprFunc is a function that given an expression will return that
|
|
// expression as is or transformed, or bool to indicate
|
|
// whether the expression was modified, and an error or nil.
|
|
type ExprFunc func(e types.PlanExpression) (types.PlanExpression, bool, error)
|
|
|
|
// TransformPlanOpExprsWithPlanOp applies a transformation function to all expressions on the given plan operator from the bottom up in the context of the plan operator
|
|
func TransformPlanOpExprsWithPlanOp(op types.PlanOperator, f ExprWithPlanOpFunc) (types.PlanOperator, bool, error) {
|
|
return TransformPlanOp(op, func(n types.PlanOperator) (types.PlanOperator, bool, error) {
|
|
return SinglePlanOpExprsWithPlanOp(n, f)
|
|
})
|
|
}
|
|
|
|
// TransformPlanOpExprs applies a transformation function to all expressions on the given plan operator from the bottom up
|
|
func TransformPlanOpExprs(op types.PlanOperator, f ExprFunc) (types.PlanOperator, bool, error) {
|
|
return TransformPlanOpExprsWithPlanOp(op, func(n types.PlanOperator, e types.PlanExpression) (types.PlanExpression, bool, error) {
|
|
return f(e)
|
|
})
|
|
}
|
|
|
|
// SinglePlanOpExprsWithPlanOp applies a transformation function to all expressions on a given plan operator in the context of that plan operator
|
|
func SinglePlanOpExprsWithPlanOp(n types.PlanOperator, f ExprWithPlanOpFunc) (types.PlanOperator, bool, error) {
|
|
ne, ok := n.(types.ContainsExpressions)
|
|
if !ok {
|
|
return n, true, nil
|
|
}
|
|
|
|
exprs := ne.Expressions()
|
|
if len(exprs) == 0 {
|
|
return n, true, nil
|
|
}
|
|
|
|
var (
|
|
newExprs []types.PlanExpression
|
|
err error
|
|
)
|
|
|
|
for i := range exprs {
|
|
e := exprs[i]
|
|
e, same, err := TransformExprWithPlanOp(n, e, f)
|
|
if err != nil {
|
|
return nil, true, err
|
|
}
|
|
if !same {
|
|
if newExprs == nil {
|
|
newExprs = make([]types.PlanExpression, len(exprs))
|
|
copy(newExprs, exprs)
|
|
}
|
|
newExprs[i] = e
|
|
}
|
|
}
|
|
|
|
if len(newExprs) > 0 {
|
|
n, err = ne.WithExpressions(newExprs...)
|
|
if err != nil {
|
|
return nil, true, err
|
|
}
|
|
return n, false, nil
|
|
}
|
|
return n, true, nil
|
|
}
|
|
|
|
// TransformSinglePlanOpExpressions applies a transformation function to all expressions on the given plan operator
|
|
func TransformSinglePlanOpExpressions(o types.PlanOperator, f ExprFunc) (types.PlanOperator, bool, error) {
|
|
e, ok := o.(types.ContainsExpressions)
|
|
if !ok {
|
|
return o, true, nil
|
|
}
|
|
|
|
exprs := e.Expressions()
|
|
if len(exprs) == 0 {
|
|
return o, true, nil
|
|
}
|
|
|
|
var newExprs []types.PlanExpression
|
|
for i := range exprs {
|
|
expr := exprs[i]
|
|
expr, same, err := TransformExpr(expr, f)
|
|
if err != nil {
|
|
return nil, true, err
|
|
}
|
|
if !same {
|
|
if newExprs == nil {
|
|
newExprs = make([]types.PlanExpression, len(exprs))
|
|
copy(newExprs, exprs)
|
|
}
|
|
newExprs[i] = expr
|
|
}
|
|
}
|
|
if len(newExprs) > 0 {
|
|
n, err := e.WithExpressions(newExprs...)
|
|
if err != nil {
|
|
return nil, true, err
|
|
}
|
|
return n, false, nil
|
|
}
|
|
return o, true, nil
|
|
}
|
|
|
|
// TransformExpr applies a transformation function to an expression
|
|
func TransformExpr(e types.PlanExpression, f ExprFunc) (types.PlanExpression, bool, error) {
|
|
children := e.Children()
|
|
if len(children) == 0 {
|
|
return f(e)
|
|
}
|
|
|
|
var (
|
|
newChildren []types.PlanExpression
|
|
err error
|
|
)
|
|
|
|
for i := 0; i < len(children); i++ {
|
|
c := children[i]
|
|
c, same, err := TransformExpr(c, f)
|
|
if err != nil {
|
|
return nil, true, err
|
|
}
|
|
if !same {
|
|
if newChildren == nil {
|
|
newChildren = make([]types.PlanExpression, len(children))
|
|
copy(newChildren, children)
|
|
}
|
|
newChildren[i] = c
|
|
}
|
|
}
|
|
|
|
sameC := true
|
|
if len(newChildren) > 0 {
|
|
sameC = false
|
|
e, err = e.WithChildren(newChildren...)
|
|
if err != nil {
|
|
return nil, true, err
|
|
}
|
|
}
|
|
|
|
e, sameN, err := f(e)
|
|
if err != nil {
|
|
return nil, true, err
|
|
}
|
|
return e, sameC && sameN, nil
|
|
}
|
|
|
|
// TransformExprWithPlanOp applies a transformation function to an expression in the context of a plan operator
|
|
func TransformExprWithPlanOp(n types.PlanOperator, e types.PlanExpression, f ExprWithPlanOpFunc) (types.PlanExpression, bool, error) {
|
|
children := e.Children()
|
|
if len(children) == 0 {
|
|
return f(n, e)
|
|
}
|
|
|
|
var (
|
|
newChildren []types.PlanExpression
|
|
err error
|
|
)
|
|
|
|
for i := 0; i < len(children); i++ {
|
|
c := children[i]
|
|
c, sameC, err := TransformExprWithPlanOp(n, c, f)
|
|
if err != nil {
|
|
return nil, true, err
|
|
}
|
|
if !sameC {
|
|
if newChildren == nil {
|
|
newChildren = make([]types.PlanExpression, len(children))
|
|
copy(newChildren, children)
|
|
}
|
|
newChildren[i] = c
|
|
}
|
|
}
|
|
|
|
sameC := true
|
|
if len(newChildren) > 0 {
|
|
sameC = false
|
|
e, err = e.WithChildren(newChildren...)
|
|
if err != nil {
|
|
return nil, true, err
|
|
}
|
|
}
|
|
|
|
e, sameN, err := f(n, e)
|
|
if err != nil {
|
|
return nil, true, err
|
|
}
|
|
return e, sameC && sameN, nil
|
|
}
|