func NewIndexOptions(columns []*IndexColumn, idxOptList []*IndexOption) *IndexOptions {
	idxOpts := &IndexOptions{
		Columns: columns,
	}
	for _, idxOpt := range idxOptList {
		switch idxOpt.Type {
		case IndexOptionComment:
			idxOpts.Comment = String(idxOpt.Val)
		case IndexOptionUsing:
			idxOpts.Using = String(idxOpt.Val)
		case IndexOptionBlockSize:
			idxOpts.BlockSize = idxOpt.Val
		case IndexOptionParser:
			idxOpts.Parser = String(idxOpt.Val)
		}
	}
	return idxOpts
}
NewIndexOptions use to create IndexOptions.
package sqlparser
import (
	"bytes"
	"encoding/hex"
	"encoding/json"
	"strconv"
	"strings"
)
func Walk(visit Visit, nodes ...SQLNode) error {
	for _, node := range nodes {
		if node == nil {
			continue
		}
		var err error
		var kontinue bool
		pre := func(cursor *Cursor) bool {
			if err != nil {
				return false
			}
			kontinue, err = visit(cursor.Node())
			if err != nil {
				return true  
			}
			return kontinue
		}
		post := func(cursor *Cursor) bool {
			return err == nil  
		}
		Rewrite(node, pre, post)
		if err != nil {
			return err
		}
	}
	return nil
}
type Visit func(node SQLNode) (kontinue bool, err error)
func Append(buf *strings.Builder, node SQLNode) {
	tbuf := &TrackedBuffer{
		Builder: buf,
	}
	node.Format(tbuf)
}
func LowerCaseTableNames(stmt SQLNode) SQLNode {
	return Rewrite(stmt, func(cursor *Cursor) bool {
		switch n := cursor.Node().(type) {
		case TableName:
			if !n.IsEmpty() {
				name := NewTableIdent(strings.ToLower(n.Name.v))
				qualifier := NewTableIdent("")
				if !n.Qualifier.IsEmpty() {
					qualifier.v = strings.ToLower(n.Qualifier.v)
				}
				tb := TableName{
					Name:      name,
					Qualifier: qualifier,
				}
				cursor.Replace(tb)
			}
			return false
		case TableIdent:
			if !n.IsEmpty() {
				id := NewTableIdent(strings.ToLower(n.v))
				cursor.Replace(id)
			}
			return false
		default:
			return true
		}
	}, nil)
}
func (node *Select) AddWhere(expr Expr) {
	if _, ok := expr.(*OrExpr); ok {
		expr = &ParenExpr{Expr: expr}
	}
	if node.Where == nil {
		node.Where = &Where{
			Type: WhereClause,
			Expr: expr,
		}
		return
	}
	node.Where.Expr = &AndExpr{
		Left:  node.Where.Expr,
		Right: expr,
	}
}
func (node *Select) AddHaving(expr Expr) {
	if _, ok := expr.(*OrExpr); ok {
		expr = &ParenExpr{Expr: expr}
	}
	if node.Having == nil {
		node.Having = &Where{
			Type: HavingClause,
			Expr: expr,
		}
		return
	}
	node.Having.Expr = &AndExpr{
		Left:  node.Having.Expr,
		Right: expr,
	}
}
type DatabaseOption struct {
	OptType string
	Value   *SQLVal
	ReadOnlyValue string
}
type TableOptionType int
const (
	TableOptionNone TableOptionType = iota
	TableOptionComment
	TableOptionEngine
	TableOptionCharset
	TableOptionAutoInc
	TableOptionAvgRowLength
	TableOptionChecksum
	TableOptionCollate
	TableOptionCompression
	TableOptionConnection
	TableOptionDataDirectory
	TableOptionIndexDirectory
	TableOptionDelayKeyWrite
	TableOptionEncryption
	TableOptionInsertMethod
	TableOptionKeyBlockSize
	TableOptionMaxRows
	TableOptionMinRows
	TableOptionPackKeys
	TableOptionPassword
	TableOptionRowFormat
	TableOptionStatsAutoRecalc
	TableOptionStatsPersistent
	TableOptionStatsSamplePages
	TableOptionTableSpace
)
func (tblOptList *TableOptionListOpt) CheckIfTableOptDuplicate() string {
	var optOnce = map[TableOptionType]bool{
		TableOptionComment:          false,
		TableOptionEngine:           false,
		TableOptionCharset:          false,
		TableOptionAutoInc:          false,
		TableOptionAvgRowLength:     false,
		TableOptionChecksum:         false,
		TableOptionCollate:          false,
		TableOptionCompression:      false,
		TableOptionConnection:       false,
		TableOptionDataDirectory:    false,
		TableOptionIndexDirectory:   false,
		TableOptionDelayKeyWrite:    false,
		TableOptionEncryption:       false,
		TableOptionInsertMethod:     false,
		TableOptionKeyBlockSize:     false,
		TableOptionMaxRows:          false,
		TableOptionMinRows:          false,
		TableOptionPackKeys:         false,
		TableOptionPassword:         false,
		TableOptionRowFormat:        false,
		TableOptionStatsAutoRecalc:  false,
		TableOptionStatsPersistent:  false,
		TableOptionStatsSamplePages: false,
	}
	for _, opt := range tblOptList.TblOptList {
		switch opt.Type {
		case TableOptionComment:
			if optOnce[TableOptionComment] {
				return "Duplicate table option for keyword 'comment', the option should only be appeared just one time in RadonDB."
			}
			optOnce[TableOptionComment] = true
		case TableOptionEngine:
			if optOnce[TableOptionEngine] {
				return "Duplicate table option for keyword 'engine', the option should only be appeared just one time in RadonDB."
			}
			optOnce[TableOptionEngine] = true
		case TableOptionCharset:
			if optOnce[TableOptionCharset] {
				return "Duplicate table option for keyword 'charset', the option should only be appeared just one time in RadonDB."
			}
			optOnce[TableOptionCharset] = true
		case TableOptionAutoInc:
			if optOnce[TableOptionAutoInc] {
				return "Duplicate table option for keyword 'auto_increment', the option should only be appeared just one time in RadonDB."
			}
			optOnce[TableOptionAutoInc] = true
		case TableOptionAvgRowLength:
			if optOnce[TableOptionAvgRowLength] {
				return "Duplicate table option for keyword 'avg_row_length', the option should only be appeared just one time in RadonDB."
			}
			optOnce[TableOptionAvgRowLength] = true
		case TableOptionChecksum:
			if optOnce[TableOptionChecksum] {
				return "Duplicate table option for keyword 'checksum', the option should only be appeared just one time in RadonDB."
			}
			optOnce[TableOptionChecksum] = true
		case TableOptionCollate:
			if optOnce[TableOptionCollate] {
				return "Duplicate table option for table option keyword 'collate', the option should only be appeared just one time in RadonDB."
			}
			optOnce[TableOptionCollate] = true
		case TableOptionCompression:
			if optOnce[TableOptionCompression] {
				return "Duplicate table option for keyword 'compression', the option should only be appeared just one time in RadonDB."
			}
			optOnce[TableOptionCompression] = true
		case TableOptionConnection:
			if optOnce[TableOptionConnection] {
				return "Duplicate table option for keyword 'connection', the option should only be appeared just one time in RadonDB."
			}
			optOnce[TableOptionConnection] = true
		case TableOptionDataDirectory:
			if optOnce[TableOptionDataDirectory] {
				return "Duplicate table option for keyword 'data directory', the option should only be appeared just one time in RadonDB."
			}
			optOnce[TableOptionDataDirectory] = true
		case TableOptionIndexDirectory:
			if optOnce[TableOptionIndexDirectory] {
				return "Duplicate table option for keyword 'index directory', the option should only be appeared just one time in RadonDB."
			}
			optOnce[TableOptionIndexDirectory] = true
		case TableOptionDelayKeyWrite:
			if optOnce[TableOptionDelayKeyWrite] {
				return "Duplicate table option for keyword 'delay_key_write', the option should only be appeared just one time in RadonDB."
			}
			optOnce[TableOptionDelayKeyWrite] = true
		case TableOptionEncryption:
			if optOnce[TableOptionEncryption] {
				return "Duplicate table option for keyword 'encryption', the option should only be appeared just one time in RadonDB."
			}
			optOnce[TableOptionEncryption] = true
		case TableOptionInsertMethod:
			if optOnce[TableOptionInsertMethod] {
				return "Duplicate table option for keyword 'insert_method', the option should only be appeared just one time in RadonDB."
			}
			optOnce[TableOptionInsertMethod] = true
		case TableOptionKeyBlockSize:
			if optOnce[TableOptionKeyBlockSize] {
				return "Duplicate table option for keyword 'key_block_size', the option should only be appeared just one time in RadonDB."
			}
			optOnce[TableOptionKeyBlockSize] = true
		case TableOptionMaxRows:
			if optOnce[TableOptionMaxRows] {
				return "Duplicate table option for keyword 'max_rows', the option should only be appeared just one time in RadonDB."
			}
			optOnce[TableOptionMaxRows] = true
		case TableOptionMinRows:
			if optOnce[TableOptionMinRows] {
				return "Duplicate table option for keyword 'min_rows', the option should only be appeared just one time in RadonDB."
			}
			optOnce[TableOptionMinRows] = true
		case TableOptionPackKeys:
			if optOnce[TableOptionPackKeys] {
				return "Duplicate table option for keyword 'pack_keys', the option should only be appeared just one time in RadonDB."
			}
			optOnce[TableOptionPackKeys] = true
		case TableOptionPassword:
			if optOnce[TableOptionPassword] {
				return "Duplicate table option for keyword 'password', the option should only be appeared just one time in RadonDB."
			}
			optOnce[TableOptionPassword] = true
		case TableOptionRowFormat:
			if optOnce[TableOptionRowFormat] {
				return "Duplicate table option for keyword 'row_format', the option should only be appeared just one time in RadonDB."
			}
			optOnce[TableOptionRowFormat] = true
		case TableOptionStatsAutoRecalc:
			if optOnce[TableOptionStatsAutoRecalc] {
				return "Duplicate table option for keyword 'stats_auto_recalc', the option should only be appeared just one time in RadonDB."
			}
			optOnce[TableOptionStatsAutoRecalc] = true
		case TableOptionStatsPersistent:
			if optOnce[TableOptionStatsPersistent] {
				return "Duplicate table option for keyword 'stats_persistent', the option should only be appeared just one time in RadonDB."
			}
			optOnce[TableOptionStatsPersistent] = true
		case TableOptionStatsSamplePages:
			if optOnce[TableOptionStatsSamplePages] {
				return "Duplicate table option for keyword 'stats_sample_pages', the option should only be appeared just one time in RadonDB."
			}
			optOnce[TableOptionStatsSamplePages] = true
		case TableOptionTableSpace:
			if optOnce[TableOptionTableSpace] {
				return "Duplicate table option for keyword 'tablespace', the option should only be appeared just one time in RadonDB."
			}
			optOnce[TableOptionTableSpace] = true
		}
	}
	return ""
}
func (tblOptList *TableOptionListOpt) GetTableOptValByType(optType TableOptionType) *SQLVal {
	for _, opt := range tblOptList.TblOptList {
		if opt.Type == optType {
			return opt.Val
		}
	}
	return nil
}
type PartitionDefinition struct {
	Backend string
	Row     ValTuple
}
type PartitionDefinitions []*PartitionDefinition
type (
	PartitionOption interface {
		PartitionType() string
	}
	PartOptGlobal struct{}
	PartOptSingle struct {
		BackendName string
	}
	PartOptNormal struct{}
	PartOptList struct {
		Name     string
		PartDefs PartitionDefinitions
	}
	PartOptHash struct {
		Name         string
		PartitionNum *SQLVal
	}
)
func (*PartOptGlobal) PartitionType() string {
	return GlobalTableType
}
func (*PartOptSingle) PartitionType() string {
	return SingleTableType
}
func (*PartOptNormal) PartitionType() string {
	return NormalTableType
}
func (*PartOptList) PartitionType() string {
	return PartitionTableList
}
func (*PartOptHash) PartitionType() string {
	return PartitionTableHash
}
type TableOption struct {
	Type TableOptionType
	Val  *SQLVal
}
type TableOptionListOpt struct {
	TblOptList []*TableOption
}
type IndexOption struct {
	Type IndexOptionType
	Val  *SQLVal
}
type IndexOptionType int
const (
	IndexOptionNone IndexOptionType = iota
	IndexOptionComment
	IndexOptionUsing
	IndexOptionBlockSize
	IndexOptionParser
)
type IndexColumn struct {
	Column ColIdent
	Length *SQLVal
}