func (u *updatableJoinUpdater) StatementBegin(ctx *sql.Context) {
	for _, v := range u.updaterMap {
		v.StatementBegin(ctx)
	}
}
StatementBegin implements the sql.TableEditor interface.
package plan
import (
	"fmt"
	"gopkg.in/src-d/go-errors.v1"
	"github.com/dolthub/go-mysql-server/sql"
)
type UpdateJoin struct {
	updaters map[string]sql.RowUpdater
	UnaryNode
}
func NewUpdateJoin(editorMap map[string]sql.RowUpdater, child sql.Node) *UpdateJoin {
	return &UpdateJoin{
		updaters:  editorMap,
		UnaryNode: UnaryNode{Child: child},
	}
}
var _ sql.Node = (*UpdateJoin)(nil)
func (u *UpdateJoin) String() string {
	pr := sql.NewTreePrinter()
	_ = pr.WriteNode("Update Join")
	_ = pr.WriteChildren(u.Child.String())
	return pr.String()
}
func (u *UpdateJoin) RowIter(ctx *sql.Context, row sql.Row) (sql.RowIter, error) {
	ji, err := u.Child.RowIter(ctx, row)
	if err != nil {
		return nil, err
	}
	return &updateJoinIter{
		ctx:              ctx,
		updateSourceIter: ji,
		joinSchema:       u.Child.(*UpdateSource).Child.Schema(),
		updaters:         u.updaters,
		caches:           make(map[string]sql.KeyValueCache),
		disposals:        make(map[string]sql.DisposeFunc),
		joinNode:         u.Child.(*UpdateSource).Child,
	}, nil
}
func (u *UpdateJoin) GetUpdatable() sql.UpdatableTable {
	return &updatableJoinTable{
		updaters: u.updaters,
		joinNode: u.Child.(*UpdateSource).Child,
	}
}
func (u *UpdateJoin) WithChildren(children ...sql.Node) (sql.Node, error) {
	if len(children) != 1 {
		return nil, sql.ErrInvalidChildrenNumber.New(u, len(children), 1)
	}
	return NewUpdateJoin(u.updaters, children[0]), nil
}
type updateJoinIter struct {
	ctx              *sql.Context
	updateSourceIter sql.RowIter
	joinSchema       sql.Schema
	updaters         map[string]sql.RowUpdater
	caches           map[string]sql.KeyValueCache
	disposals        map[string]sql.DisposeFunc
	joinNode         sql.Node
}
var _ sql.RowIter = (*updateJoinIter)(nil)
func (u *updateJoinIter) Next() (sql.Row, error) {
	for {
		oldAndNewRow, err := u.updateSourceIter.Next()
		if err != nil {
			return nil, err
		}
		oldJoinRow, newJoinRow := oldAndNewRow[:len(oldAndNewRow)/2], oldAndNewRow[len(oldAndNewRow)/2:]
		tableToOldRowMap := splitRowIntoTableRowMap(oldJoinRow, u.joinSchema)
		tableToNewRowMap := splitRowIntoTableRowMap(newJoinRow, u.joinSchema)
		for tableName, _ := range u.updaters {
			oldTableRow := tableToOldRowMap[tableName]
			if isRightOrLeftJoin(u.joinNode) {
				works, err := u.shouldUpdateDirectionalJoin(u.ctx, oldJoinRow, oldTableRow)
				if err != nil {
					return nil, err
				}
				if !works {
					tableToNewRowMap[tableName] = oldTableRow
					continue
				}
			}
			cache := u.getOrCreateCache(u.ctx, tableName)
			hash, err := sql.HashOf(oldTableRow)
			if err != nil {
				return nil, err
			}
			_, err = cache.Get(hash)
			if errors.Is(err, sql.ErrKeyNotFound) {
				cache.Put(hash, struct{}{})
				continue
			} else if err != nil {
				return nil, err
			}
			tableToNewRowMap[tableName] = oldTableRow
		}
		newJoinRow = recreateRowFromMap(tableToNewRowMap, u.joinSchema)
		equals, err := oldJoinRow.Equals(newJoinRow, u.joinSchema)
		if err != nil {
			return nil, err
		}
		if !equals {
			return append(oldJoinRow, newJoinRow...), nil
		}
	}
}
func (u *updateJoinIter) shouldUpdateDirectionalJoin(ctx *sql.Context, joinRow, tableRow sql.Row) (bool, error) {
	jn := u.joinNode.(JoinNode)
	var cond sql.Expression
	switch n := jn.(type) {
	case *RightJoin:
		cond = n.Cond
	case *LeftJoin:
		cond = n.Cond
	default:
		return true, fmt.Errorf("error: should only consider left or right join.")
	}
	val, err := cond.Eval(ctx, joinRow)
	if err != nil {
		return true, err
	}
	if val.(bool) {
		return true, nil
	}
	for _, v := range tableRow {
		if v != nil {
			return true, nil
		}
	}
	return false, nil
}
func (u *updateJoinIter) Close(context *sql.Context) error {
	for _, disposeF := range u.disposals {
		disposeF()
	}
	return u.updateSourceIter.Close(context)
}
func (u *updateJoinIter) getOrCreateCache(ctx *sql.Context, tableName string) sql.KeyValueCache {
	potential, exists := u.caches[tableName]
	if exists {
		return potential
	}
	cache, disposal := ctx.Memory.NewHistoryCache()
	u.caches[tableName] = cache
	u.disposals[tableName] = disposal
	return cache
}
type updatableJoinTable struct {
	updaters map[string]sql.RowUpdater
	joinNode sql.Node
}
var _ sql.UpdatableTable = (*updatableJoinTable)(nil)
func (u *updatableJoinTable) Partitions(context *sql.Context) (sql.PartitionIter, error) {
	panic("this method should not be called")
}
func (u *updatableJoinTable) PartitionRows(context *sql.Context, partition sql.Partition) (sql.RowIter, error) {
	panic("this method should not be called")
}
func (u *updatableJoinTable) Name() string {
	panic("this method should not be called")
}
func (u *updatableJoinTable) String() string {
	panic("this method should not be called")
}
func (u *updatableJoinTable) Schema() sql.Schema {
	return u.joinNode.Schema()
}
func (u *updatableJoinTable) Updater(ctx *sql.Context) sql.RowUpdater {
	return &updatableJoinUpdater{
		updaterMap: u.updaters,
		schemaMap:  recreateTableSchemaFromJoinSchema(u.joinNode.Schema()),
		joinSchema: u.joinNode.Schema(),
	}
}
type updatableJoinUpdater struct {
	updaterMap map[string]sql.RowUpdater
	schemaMap  map[string]sql.Schema
	joinSchema sql.Schema
}
var _ sql.RowUpdater = (*updatableJoinUpdater)(nil)