func (cv *CreateView) String() string {
	pr := sql.NewTreePrinter()
	_ = pr.WriteNode("CreateView(%s)", cv.Name)
	_ = pr.WriteChildren(
		fmt.Sprintf("Columns (%s)", strings.Join(cv.Columns, ", ")),
		cv.Child.String(),
	)
	return pr.String()
}
String implements the fmt.Stringer interface, using sql.TreePrinter to
generate the string.
package plan
import (
	"fmt"
	"strings"
	"github.com/dolthub/go-mysql-server/sql"
)
type CreateView struct {
	UnaryNode
	database   sql.Database
	Name       string
	Columns    []string
	IsReplace  bool
	Definition *SubqueryAlias
}
func NewCreateView(
	database sql.Database,
	name string,
	columns []string,
	definition *SubqueryAlias,
	isReplace bool,
) *CreateView {
	return &CreateView{
		UnaryNode:  UnaryNode{Child: definition},
		database:   database,
		Name:       name,
		Columns:    columns,
		IsReplace:  isReplace,
		Definition: definition,
	}
}
func (cv *CreateView) View() *sql.View {
	return cv.Definition.AsView()
}
func (cv *CreateView) Children() []sql.Node {
	return []sql.Node{cv.Child}
}
func (cv *CreateView) Resolved() bool {
	_, ok := cv.database.(sql.UnresolvedDatabase)
	return !ok && cv.Child.Resolved()
}
func (cv *CreateView) RowIter(ctx *sql.Context, row sql.Row) (sql.RowIter, error) {
	view := cv.View()
	registry := ctx.GetViewRegistry()
	if cv.IsReplace {
		if dropper, ok := cv.database.(sql.ViewDatabase); ok {
			err := dropper.DropView(ctx, cv.Name)
			if err != nil && !sql.ErrViewDoesNotExist.Is(err) {
				return sql.RowsToRowIter(), err
			}
		} else {
			err := registry.Delete(cv.database.Name(), view.Name())
			if err != nil && !sql.ErrViewDoesNotExist.Is(err) {
				return sql.RowsToRowIter(), err
			}
		}
	}
	creator, ok := cv.database.(sql.ViewDatabase)
	if ok {
		return sql.RowsToRowIter(), creator.CreateView(ctx, cv.Name, cv.Definition.TextDefinition)
	} else {
		return sql.RowsToRowIter(), registry.Register(cv.database.Name(), view)
	}
}
func (cv *CreateView) Schema() sql.Schema { return nil }