func (node TableIdent) CompliantName() string {
	return compliantName(node.v)
}
CompliantName returns a compliant id name
that can be used for a bind var.
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
}
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
}
type LockOptionType byte
const (
	LockOptionEmpty LockOptionType = iota + 1
	LockOptionNone
	LockOptionDefault
	LockOptionShared
	LockOptionExclusive
)
func (n LockOptionType) String() string {
	switch n {
	case LockOptionNone:
		return "none"
	case LockOptionDefault:
		return "default"
	case LockOptionShared:
		return "shared"
	case LockOptionExclusive:
		return "exclusive"
	default:
		return ""
	}
}
type AlgorithmOptionType byte
const (
	AlgorithmOptionEmpty AlgorithmOptionType = iota
	AlgorithmOptionDefault
	AlgorithmOptionCopy
	AlgorithmOptionInplace
	AlgorithmOptionInstant
)
func (a AlgorithmOptionType) String() string {
	switch a {
	case AlgorithmOptionDefault:
		return "default"
	case AlgorithmOptionCopy:
		return "copy"
	case AlgorithmOptionInplace:
		return "inplace"
	case AlgorithmOptionInstant:
		return "instant"
	default:
		return ""
	}
}
func (ts *TableSpec) AddColumn(cd *ColumnDefinition) {
	ts.Columns = append(ts.Columns, cd)
}
func (ts *TableSpec) AddIndex(id *IndexDefinition) {
	ts.Indexes = append(ts.Indexes, id)
}
type ColumnOptionListOpt struct {
	ColOptList []*ColumnOption
}
type ColumnOption struct {
	typ ColumnOpt
	NotNull       BoolVal
	Autoincrement BoolVal
	Default       *SQLVal
	Comment       *SQLVal
	OnUpdate      string
	Collate       *SQLVal
	ColumnFormat  string
	Storage       string
	PrimaryKeyOpt ColumnPrimaryKeyOption
	UniqueKeyOpt  ColumnUniqueKeyOption
}
type ColumnPrimaryKeyOption int
const (
	ColKeyPrimaryNone ColumnPrimaryKeyOption = iota
	ColKeyPrimary
)
type ColumnUniqueKeyOption int
const (
	ColKeyUniqueNone ColumnUniqueKeyOption = iota
	ColKeyUniqueKey
)
type ColumnOpt int
const (
	ColumnOptionNone ColumnOpt = iota
	ColumnOptionNotNull
	ColumnOptionAutoincrement
	ColumnOptionDefault
	ColumnOptionComment
	ColumnOptionOnUpdate
	ColumnOptionKeyPrimaryOpt
	ColumnOptionKeyUniqueOpt
	ColumnOptionCollate
	ColumnOptionFormat
	ColumnOptionStorage
)
func (col ColumnOption) GetOptType() ColumnOpt {
	return col.typ
}
func (co *ColumnOptionListOpt) GetColumnOption(opt ColumnOpt) *ColumnOption {
	for _, val := range co.ColOptList {
		if val.typ == opt {
			return val
		}
	}
	return &ColumnOption{
		typ:           ColumnOptionNone,
		NotNull:       false,
		Autoincrement: false,
		Default:       nil,
		Comment:       nil,
		OnUpdate:      "",
		Collate:       nil,
		ColumnFormat:  "",
		Storage:       "",
		PrimaryKeyOpt: ColKeyPrimaryNone,
		UniqueKeyOpt:  ColKeyUniqueNone,
	}
}
func (node Columns) FindColumn(col ColIdent) int {
	for i, colName := range node {
		if colName.Equal(col) {
			return i
		}
	}
	return -1
}
type LengthScaleOption struct {
	Length *SQLVal
	Scale  *SQLVal
}
type ValType int
const (
	StrVal = ValType(iota)
	IntVal
	FloatVal
	HexNum
	HexVal
	ValArg
	StrValWithoutQuote
)
func NewStrVal(in []byte) *SQLVal {
	return &SQLVal{Type: StrVal, Val: in}
}
func NewStrValWithoutQuote(in []byte) *SQLVal {
	return &SQLVal{Type: StrValWithoutQuote, Val: in}
}
func NewIntVal(in []byte) *SQLVal {
	return &SQLVal{Type: IntVal, Val: in}
}
func NewFloatVal(in []byte) *SQLVal {
	return &SQLVal{Type: FloatVal, Val: in}
}
func NewHexNum(in []byte) *SQLVal {
	return &SQLVal{Type: HexNum, Val: in}
}
func NewHexVal(in []byte) *SQLVal {
	return &SQLVal{Type: HexVal, Val: in}
}
func NewValArg(in []byte) *SQLVal {
	return &SQLVal{Type: ValArg, Val: in}
}
func (node *SQLVal) HexDecode() ([]byte, error) {
	dst := make([]byte, hex.DecodedLen(len([]byte(node.Val))))
	_, err := hex.Decode(dst, []byte(node.Val))
	if err != nil {
		return nil, err
	}
	return dst, err
}
func (node TableName) IsEmpty() bool {
	return node.Name.IsEmpty()
}
func NewWhere(typ WhereTypeEnum, expr Expr) *Where {
	if expr == nil {
		return nil
	}
	return &Where{Type: typ, Expr: expr}
}
func ReplaceExpr(root, from, to Expr) Expr {
	tmp := Rewrite(root, replaceExpr(from, to), nil)
	expr, success := tmp.(Expr)
	if !success {
		return from
	}
	return expr
}
func replaceExpr(from, to Expr) func(cursor *Cursor) bool {
	return func(cursor *Cursor) bool {
		if cursor.Node() == from {
			cursor.Replace(to)
		}
		switch cursor.Node().(type) {
		case *ExistsExpr, *SQLVal, *Subquery, *ValuesFuncExpr, *Default:
			return false
		}
		return true
	}
}
func CloneSelectExpr(node SelectExpr) SelectExpr {
	if node == nil {
		return nil
	}
	return node.clone()
}
func CloneExpr(node Expr) Expr {
	if node == nil {
		return nil
	}
	return node.clone()
}
func (node *ColName) Equal(c *ColName) bool {
	if node == nil || c == nil {
		return false
	}
	return node.Name.Equal(c.Name) && node.Qualifier == c.Qualifier
}
var Aggregates = map[string]bool{
	"avg":          true,
	"bit_and":      true,
	"bit_or":       true,
	"bit_xor":      true,
	"count":        true,
	"group_concat": true,
	"max":          true,
	"min":          true,
	"std":          true,
	"stddev_pop":   true,
	"stddev_samp":  true,
	"stddev":       true,
	"sum":          true,
	"var_pop":      true,
	"var_samp":     true,
	"variance":     true,
}
func (node *FuncExpr) IsAggregate() bool {
	return Aggregates[node.Name.Lowered()]
}
func NewColIdent(str string) ColIdent {
	return ColIdent{
		val: str,
	}
}
func (node ColIdent) IsEmpty() bool {
	return node.val == ""
}
func (node ColIdent) String() string {
	return node.val
}
func (node ColIdent) CompliantName() string {
	return compliantName(node.val)
}
func (node ColIdent) Lowered() string {
	if node.val == "" {
		return ""
	}
	if node.lowered == "" {
		node.lowered = strings.ToLower(node.val)
	}
	return node.lowered
}
func (node ColIdent) Equal(in ColIdent) bool {
	return node.Lowered() == in.Lowered()
}
func (node ColIdent) EqualString(str string) bool {
	return node.Lowered() == strings.ToLower(str)
}
func (node ColIdent) MarshalJSON() ([]byte, error) {
	return json.Marshal(node.val)
}
func (node *ColIdent) UnmarshalJSON(b []byte) error {
	var result string
	err := json.Unmarshal(b, &result)
	if err != nil {
		return err
	}
	node.val = result
	return nil
}
func NewTableIdent(str string) TableIdent {
	return TableIdent{v: str}
}
func (node TableIdent) IsEmpty() bool {
	return node.v == ""
}
func (node TableIdent) String() string {
	return node.v
}