func getForeignKeyTable(t sql.Table) sql.ForeignKeyTable {
	switch t := t.(type) {
	case sql.ForeignKeyTable:
		return t
	case sql.TableWrapper:
		return getForeignKeyTable(t.Underlying())
	default:
		return nil
	}
}
getForeignKeyTable returns the underlying ForeignKeyTable for the table given, or nil if it isn't a ForeignKeyTable
package plan
import (
	"fmt"
	"io"
	"strings"
	"gopkg.in/src-d/go-errors.v1"
	"github.com/dolthub/go-mysql-server/sql"
)
var ErrNotView = errors.NewKind("'%' is not VIEW")
type ShowCreateTable struct {
	*UnaryNode
	IsView  bool
	Indexes []sql.Index
	Checks  sql.CheckConstraints
}
func NewShowCreateTable(table sql.Node, isView bool) sql.Node {
	return &ShowCreateTable{
		UnaryNode: &UnaryNode{table},
		IsView:    isView,
	}
}
func (n *ShowCreateTable) Resolved() bool {
	return true
}
func (n *ShowCreateTable) WithChildren(children ...sql.Node) (sql.Node, error) {
	if len(children) != 1 {
		return nil, sql.ErrInvalidChildrenNumber.New(1, len(children))
	}
	child := children[0]
	switch child.(type) {
	case *SubqueryAlias, *ResolvedTable, *UnresolvedTable:
	default:
		return nil, sql.ErrInvalidChildType.New(n, child, (*SubqueryAlias)(nil))
	}
	nc := *n
	nc.Child = child
	return &nc, nil
}
func (n *ShowCreateTable) Schema() sql.Schema {
	switch n.Child.(type) {
	case *SubqueryAlias:
		return sql.Schema{
			&sql.Column{Name: "View", Type: sql.LongText, Nullable: false},
			&sql.Column{Name: "Create View", Type: sql.LongText, Nullable: false},
		}
	case *ResolvedTable, *UnresolvedTable:
		return sql.Schema{
			&sql.Column{Name: "Table", Type: sql.LongText, Nullable: false},
			&sql.Column{Name: "Create Table", Type: sql.LongText, Nullable: false},
		}
	default:
		panic(fmt.Sprintf("unexpected type %T", n.Child))
	}
}
func (n *ShowCreateTable) RowIter(ctx *sql.Context, row sql.Row) (sql.RowIter, error) {
	return &showCreateTablesIter{
		ctx:     ctx,
		table:   n.Child,
		isView:  n.IsView,
		indexes: n.Indexes,
		checks:  n.Checks,
	}, nil
}
func (n *ShowCreateTable) String() string {
	t := "TABLE"
	if n.IsView {
		t = "VIEW"
	}
	name := ""
	if nameable, ok := n.Child.(sql.Nameable); ok {
		name = nameable.Name()
	}
	return fmt.Sprintf("SHOW CREATE %s %s", t, name)
}
type showCreateTablesIter struct {
	table        sql.Node
	didIteration bool
	isView       bool
	ctx          *sql.Context
	indexes      []sql.Index
	checks       sql.CheckConstraints
}
func (i *showCreateTablesIter) Next() (sql.Row, error) {
	if i.didIteration {
		return nil, io.EOF
	}
	i.didIteration = true
	var composedCreateTableStatement string
	var tableName string
	switch table := i.table.(type) {
	case *ResolvedTable:
		if i.isView {
			return nil, ErrNotView.New(table.Name())
		}
		tableName = table.Name()
		var err error
		composedCreateTableStatement, err = i.produceCreateTableStatement(table.Table)
		if err != nil {
			return nil, err
		}
	case *SubqueryAlias:
		tableName = table.Name()
		composedCreateTableStatement = produceCreateViewStatement(table)
	default:
		panic(fmt.Sprintf("unexpected type %T", i.table))
	}
	return sql.NewRow(
		tableName,                     
		composedCreateTableStatement,  
	), nil
}
type NameAndSchema interface {
	sql.Nameable
	Schema() sql.Schema
}
func (i *showCreateTablesIter) produceCreateTableStatement(table sql.Table) (string, error) {
	schema := table.Schema()
	colStmts := make([]string, len(schema))
	var primaryKeyCols []string
	for i, col := range schema {
		stmt := fmt.Sprintf("  `%s` %s", col.Name, strings.ToLower(col.Type.String()))
		if !col.Nullable {
			stmt = fmt.Sprintf("%s NOT NULL", stmt)
		}
		if col.AutoIncrement {
			stmt = fmt.Sprintf("%s AUTO_INCREMENT", stmt)
		}
		if col.Default != nil {
			stmt = fmt.Sprintf("%s DEFAULT %s", stmt, col.Default.String())
		}
		if col.Comment != "" {
			stmt = fmt.Sprintf("%s COMMENT '%s'", stmt, col.Comment)
		}
		if col.PrimaryKey {
			primaryKeyCols = append(primaryKeyCols, col.Name)
		}
		colStmts[i] = stmt
	}
	if len(primaryKeyCols) > 0 {
		primaryKey := fmt.Sprintf("  PRIMARY KEY (%s)", strings.Join(quoteIdentifiers(primaryKeyCols), ","))
		colStmts = append(colStmts, primaryKey)
	}
	for _, index := range i.indexes {
		if isPrimaryKeyIndex(index, table) {
			continue
		}
		var indexCols []string
		for _, expr := range index.Expressions() {
			col := GetColumnFromIndexExpr(expr, table)
			if col != nil {
				indexCols = append(indexCols, fmt.Sprintf("`%s`", col.Name))
			}
		}
		unique := ""
		if index.IsUnique() {
			unique = "UNIQUE "
		}
		key := fmt.Sprintf("  %sKEY `%s` (%s)", unique, index.ID(), strings.Join(indexCols, ","))
		if index.Comment() != "" {
			key = fmt.Sprintf("%s COMMENT '%s'", key, index.Comment())
		}
		colStmts = append(colStmts, key)
	}
	fkt := getForeignKeyTable(table)
	if fkt != nil {
		fks, err := fkt.GetForeignKeys(i.ctx)
		if err != nil {
			return "", err
		}
		for _, fk := range fks {
			keyCols := strings.Join(quoteIdentifiers(fk.Columns), ",")
			refCols := strings.Join(quoteIdentifiers(fk.ReferencedColumns), ",")
			onDelete := ""
			if len(fk.OnDelete) > 0 && fk.OnDelete != sql.ForeignKeyReferenceOption_DefaultAction {
				onDelete = " ON DELETE " + string(fk.OnDelete)
			}
			onUpdate := ""
			if len(fk.OnUpdate) > 0 && fk.OnUpdate != sql.ForeignKeyReferenceOption_DefaultAction {
				onUpdate = " ON UPDATE " + string(fk.OnUpdate)
			}
			colStmts = append(colStmts, fmt.Sprintf("  CONSTRAINT `%s` FOREIGN KEY (%s) REFERENCES `%s` (%s)%s%s", fk.Name, keyCols, fk.ReferencedTable, refCols, onDelete, onUpdate))
		}
	}
	if i.checks != nil {
		for _, check := range i.checks {
			fmted := fmt.Sprintf("  CONSTRAINT `%s` CHECK %s", check.Name, check.Expr.String())
			if !check.Enforced {
				fmted += " /*!80016 NOT ENFORCED */"
			}
			colStmts = append(colStmts, fmted)
		}
	}
	return fmt.Sprintf(
		"CREATE TABLE `%s` (\n%s\n) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4",
		table.Name(),
		strings.Join(colStmts, ",\n"),
	), nil
}