// Copyright 2021 Molecula Corp. All rights reserved.
package sql2

import (
	"bytes"
	"fmt"
	"strings"
)

type Node interface {
	node()
	fmt.Stringer
}

func (*AlterTableStatement) node()    {}
func (*AnalyzeStatement) node()       {}
func (*Assignment) node()             {}
func (*BeginStatement) node()         {}
func (*BinaryExpr) node()             {}
func (*BindExpr) node()               {}
func (*BlobLit) node()                {}
func (*BoolLit) node()                {}
func (*Call) node()                   {}
func (*CaseBlock) node()              {}
func (*CaseExpr) node()               {}
func (*CastExpr) node()               {}
func (*CheckConstraint) node()        {}
func (*ColumnDefinition) node()       {}
func (*CommitStatement) node()        {}
func (*CreateIndexStatement) node()   {}
func (*CreateTableStatement) node()   {}
func (*CreateTriggerStatement) node() {}
func (*CreateViewStatement) node()    {}
func (*DefaultConstraint) node()      {}
func (*DeleteStatement) node()        {}
func (*DropIndexStatement) node()     {}
func (*DropTableStatement) node()     {}
func (*DropTriggerStatement) node()   {}
func (*DropViewStatement) node()      {}
func (*Exists) node()                 {}
func (*ExplainStatement) node()       {}
func (*ExprList) node()               {}
func (*FilterClause) node()           {}
func (*ForeignKeyArg) node()          {}
func (*ForeignKeyConstraint) node()   {}
func (*FrameSpec) node()              {}
func (*Ident) node()                  {}
func (*IndexedColumn) node()          {}
func (*InsertStatement) node()        {}
func (*JoinClause) node()             {}
func (*JoinOperator) node()           {}
func (*NotNullConstraint) node()      {}
func (*NullLit) node()                {}
func (*NumberLit) node()              {}
func (*OnConstraint) node()           {}
func (*OrderingTerm) node()           {}
func (*OverClause) node()             {}
func (*ParenExpr) node()              {}
func (*ParenSource) node()            {}
func (*PrimaryKeyConstraint) node()   {}
func (*QualifiedRef) node()           {}
func (*QualifiedTableName) node()     {}
func (*Raise) node()                  {}
func (*Range) node()                  {}
func (*ReleaseStatement) node()       {}
func (*ResultColumn) node()           {}
func (*RollbackStatement) node()      {}
func (*SavepointStatement) node()     {}
func (*SelectStatement) node()        {}
func (*StringLit) node()              {}
func (*Type) node()                   {}
func (*UnaryExpr) node()              {}
func (*UniqueConstraint) node()       {}
func (*UpdateStatement) node()        {}
func (*UpsertClause) node()           {}
func (*UsingConstraint) node()        {}
func (*Window) node()                 {}
func (*WindowDefinition) node()       {}
func (*WithClause) node()             {}

type Statement interface {
	Node
	stmt()
}

func (*AlterTableStatement) stmt()    {}
func (*AnalyzeStatement) stmt()       {}
func (*BeginStatement) stmt()         {}
func (*CommitStatement) stmt()        {}
func (*CreateIndexStatement) stmt()   {}
func (*CreateTableStatement) stmt()   {}
func (*CreateTriggerStatement) stmt() {}
func (*CreateViewStatement) stmt()    {}
func (*DeleteStatement) stmt()        {}
func (*DropIndexStatement) stmt()     {}
func (*DropTableStatement) stmt()     {}
func (*DropTriggerStatement) stmt()   {}
func (*DropViewStatement) stmt()      {}
func (*ExplainStatement) stmt()       {}
func (*InsertStatement) stmt()        {}
func (*ReleaseStatement) stmt()       {}
func (*RollbackStatement) stmt()      {}
func (*SavepointStatement) stmt()     {}
func (*SelectStatement) stmt()        {}
func (*UpdateStatement) stmt()        {}

// CloneStatement returns a deep copy stmt.
func CloneStatement(stmt Statement) Statement {
	if stmt == nil {
		return nil
	}

	switch stmt := stmt.(type) {
	case *AlterTableStatement:
		return stmt.Clone()
	case *AnalyzeStatement:
		return stmt.Clone()
	case *BeginStatement:
		return stmt.Clone()
	case *CommitStatement:
		return stmt.Clone()
	case *CreateIndexStatement:
		return stmt.Clone()
	case *CreateTableStatement:
		return stmt.Clone()
	case *CreateTriggerStatement:
		return stmt.Clone()
	case *CreateViewStatement:
		return stmt.Clone()
	case *DeleteStatement:
		return stmt.Clone()
	case *DropIndexStatement:
		return stmt.Clone()
	case *DropTableStatement:
		return stmt.Clone()
	case *DropTriggerStatement:
		return stmt.Clone()
	case *DropViewStatement:
		return stmt.Clone()
	case *ExplainStatement:
		return stmt.Clone()
	case *InsertStatement:
		return stmt.Clone()
	case *ReleaseStatement:
		return stmt.Clone()
	case *RollbackStatement:
		return stmt.Clone()
	case *SavepointStatement:
		return stmt.Clone()
	case *SelectStatement:
		return stmt.Clone()
	case *UpdateStatement:
		return stmt.Clone()
	default:
		panic(fmt.Sprintf("invalid statement type: %T", stmt))
	}
}

func cloneStatements(a []Statement) []Statement {
	if a == nil {
		return nil
	}
	other := make([]Statement, len(a))
	for i := range a {
		other[i] = CloneStatement(a[i])
	}
	return other
}

// StatementSource returns the root statement for a statement.
func StatementSource(stmt Statement) Source {
	switch stmt := stmt.(type) {
	case *SelectStatement:
		return stmt.Source
	case *UpdateStatement:
		return stmt.Table
	case *DeleteStatement:
		return stmt.Table
	default:
		return nil
	}
}

// Data types
const (
	DataTypeBool      = "BOOL"
	DataTypeDecimal   = "DECIMAL"
	DataTypeInt       = "INT"
	DataTypeSet       = "SET"
	DataTypeText      = "TEXT"
	DataTypeTimestamp = "TIMESTAMP"
)

// IsDataTypeValid returns true if typ is a valid data type.
func IsDataTypeValid(typ string) bool {
	switch typ {
	case DataTypeBool, DataTypeInt, DataTypeDecimal, DataTypeText:
		return true
	default:
		return false
	}
}

type Expr interface {
	Node
	expr()

	IsAggregate() bool
}

func (*BinaryExpr) expr()   {}
func (*BindExpr) expr()     {}
func (*BlobLit) expr()      {}
func (*BoolLit) expr()      {}
func (*Call) expr()         {}
func (*CaseExpr) expr()     {}
func (*CastExpr) expr()     {}
func (*Exists) expr()       {}
func (*ExprList) expr()     {}
func (*Ident) expr()        {}
func (*NullLit) expr()      {}
func (*NumberLit) expr()    {}
func (*ParenExpr) expr()    {}
func (*QualifiedRef) expr() {}
func (*Raise) expr()        {}
func (*Range) expr()        {}
func (*StringLit) expr()    {}
func (*UnaryExpr) expr()    {}

// CloneExpr returns a deep copy expr.
func CloneExpr(expr Expr) Expr {
	if expr == nil {
		return nil
	}

	switch expr := expr.(type) {
	case *BinaryExpr:
		return expr.Clone()
	case *BindExpr:
		return expr.Clone()
	case *BlobLit:
		return expr.Clone()
	case *BoolLit:
		return expr.Clone()
	case *Call:
		return expr.Clone()
	case *CaseExpr:
		return expr.Clone()
	case *CastExpr:
		return expr.Clone()
	case *Exists:
		return expr.Clone()
	case *ExprList:
		return expr.Clone()
	case *Ident:
		return expr.Clone()
	case *NullLit:
		return expr.Clone()
	case *NumberLit:
		return expr.Clone()
	case *ParenExpr:
		return expr.Clone()
	case *QualifiedRef:
		return expr.Clone()
	case *Raise:
		return expr.Clone()
	case *Range:
		return expr.Clone()
	case *StringLit:
		return expr.Clone()
	case *UnaryExpr:
		return expr.Clone()
	default:
		panic(fmt.Sprintf("invalid expr type: %T", expr))
	}
}

func cloneExprs(a []Expr) []Expr {
	if a == nil {
		return nil
	}
	other := make([]Expr, len(a))
	for i := range a {
		other[i] = CloneExpr(a[i])
	}
	return other
}

// ExprDataType returns the data type for an expression.
func ExprDataType(expr Expr) string {
	if expr == nil {
		return ""
	}

	switch expr := expr.(type) {
	// Simple type assertions
	case *BindExpr, *ExprList, *Ident, *NullLit, *Raise:
		return ""
	case *BlobLit, *StringLit:
		return DataTypeText
	case *BoolLit, *Exists, *Range:
		return DataTypeBool
	case *NumberLit:
		return DataTypeInt

	// Complex type assertions
	case *BinaryExpr:
		return ExprDataType(expr.X)
	case *Call:
		return DataTypeInt // TODO: May be different for some aggregations
	case *CaseExpr:
		if len(expr.Blocks) > 0 {
			return ExprDataType(expr.Blocks[0].Body)
		} else if expr.ElseExpr != nil {
			return ExprDataType(expr.ElseExpr)
		}
		return ""
	case *CastExpr:
		return "" // TODO: Inspect expr.Type.Name
	case *ParenExpr:
		return ExprDataType(expr.X)
	case *QualifiedRef:
		return expr.DataType
	case *UnaryExpr:
		return ExprDataType(expr.X)

	default:
		panic(fmt.Sprintf("invalid expr type: %T", expr))
	}
}

// ExprString returns the string representation of expr.
// Returns a blank string if expr is nil.
func ExprString(expr Expr) string {
	if expr == nil {
		return ""
	}
	return expr.String()
}

// ExprTableName returns the name of the table referenced in an expression.
// Returns ok as false if more than one table referenced. Returns a blank string
// if no tables are referenced.
func ExprTableName(expr Expr) (table string, ok bool) {
	switch expr := expr.(type) {
	case *BindExpr, *BlobLit, *BoolLit, *Ident, *NullLit, *NumberLit, *StringLit:
		return "", true

	case *BinaryExpr:
		x, ok := ExprTableName(expr.X)
		if !ok {
			return "", false
		}

		y, ok := ExprTableName(expr.Y)
		if !ok {
			return "", false
		}

		if x == "" {
			return y, true
		} else if y == "" {
			return x, true
		} else if x == y {
			return x, true
		}
		return "", false

	case *Call:
		for _, arg := range expr.Args {
			tbl, ok := ExprTableName(arg)
			if !ok || (table != "" && tbl != table) {
				return "", false
			}
			table = tbl
		}
		return table, true

	case *CaseExpr:
		tbl, ok := ExprTableName(expr.Operand)
		if !ok || (table != "" && tbl != table) {
			return "", false
		}
		table = tbl

		tbl, ok = ExprTableName(expr.ElseExpr)
		if !ok || (table != "" && tbl != table) {
			return "", false
		}
		table = tbl

		for _, blk := range expr.Blocks {
			tbl, ok := ExprTableName(blk.Condition)
			if !ok || (table != "" && tbl != table) {
				return "", false
			}
			table = tbl

			tbl, ok = ExprTableName(blk.Body)
			if !ok || (table != "" && tbl != table) {
				return "", false
			}
			table = tbl
		}
		return table, true

	case *CastExpr:
		return ExprTableName(expr.X)

	case *Exists:
		return "", false // TODO

	case *ExprList:
		for _, e := range expr.Exprs {
			tbl, ok := ExprTableName(e)
			if !ok || (table != "" && tbl != table) {
				return "", false
			}
			table = tbl
		}
		return table, true

	case *ParenExpr:
		return ExprTableName(expr.X)

	case *QualifiedRef:
		return expr.Table.Name, true

	case *Raise:
		return "", true

	case *Range:
		tbl, ok := ExprTableName(expr.X)
		if !ok || (table != "" && tbl != table) {
			return "", false
		}
		table = tbl

		tbl, ok = ExprTableName(expr.Y)
		if !ok || (table != "" && tbl != table) {
			return "", false
		}
		table = tbl
		return table, true

	case *UnaryExpr:
		return ExprTableName(expr.X)

	default:
		return "", false
	}
}

// SplitExprTree splits apart expr so it is a list of all AND joined expressions.
// For example, the expression "A AND B AND (C OR (D AND E))" would be split into
// a list of "A", "B", "C OR (D AND E)".
func SplitExprTree(expr Expr) []Expr {
	if expr == nil {
		return nil
	}

	var a []Expr
	splitExprTree(expr, &a)
	return a
}

func splitExprTree(expr Expr, a *[]Expr) {
	switch expr := expr.(type) {
	case *BinaryExpr:
		if expr.Op != AND {
			*a = append(*a, expr)
			return
		}
		splitExprTree(expr.X, a)
		splitExprTree(expr.Y, a)
	case *ParenExpr:
		splitExprTree(expr.X, a)
	default:
		*a = append(*a, expr)
	}
}

// Scope represents a context for name resolution.
// Names can be resolved at the current source or in parent scopes.
type Scope struct {
	Parent *Scope
	Source Source
}

// Source represents a table or subquery.
type Source interface {
	Node
	source()
}

func (*JoinClause) source()         {}
func (*ParenSource) source()        {}
func (*QualifiedTableName) source() {}
func (*SelectStatement) source()    {}

// CloneSource returns a deep copy src.
func CloneSource(src Source) Source {
	if src == nil {
		return nil
	}

	switch src := src.(type) {
	case *JoinClause:
		return src.Clone()
	case *ParenSource:
		return src.Clone()
	case *QualifiedTableName:
		return src.Clone()
	case *SelectStatement:
		return src.Clone()
	default:
		panic(fmt.Sprintf("invalid source type: %T", src))
	}
}

// SourceName returns the name of the source.
// Only returns for QualifiedTableName & ParenSource.
func SourceName(src Source) string {
	switch src := src.(type) {
	case *JoinClause, *SelectStatement:
		return ""
	case *ParenSource:
		return IdentName(src.Alias)
	case *QualifiedTableName:
		return src.TableName()
	default:
		return ""
	}
}

// SourceList returns a list of scopes in the current scope.
func SourceList(src Source) []Source {
	var a []Source
	ForEachSource(src, func(s Source) bool {
		a = append(a, s)
		return true
	})
	return a
}

// ForEachSource calls fn for every source within the current scope.
// Stops iteration if fn returns false.
func ForEachSource(src Source, fn func(Source) bool) {
	forEachSource(src, fn)
}

func forEachSource(src Source, fn func(Source) bool) bool {
	if !fn(src) {
		return false
	}

	switch src := src.(type) {
	case *JoinClause:
		if !forEachSource(src.X, fn) {
			return false
		} else if !forEachSource(src.Y, fn) {
			return false
		}
	case *SelectStatement:
		if !forEachSource(src.Source, fn) {
			return false
		}
	}
	return true
}

// ResolveSource returns a source with the given name.
// This can either be the table name or the alias for a source.
func ResolveSource(root Source, name string) Source {
	var ret Source
	ForEachSource(root, func(src Source) bool {
		switch src := src.(type) {
		case *ParenSource:
			if IdentName(src.Alias) == name {
				ret = src
			}
		case *QualifiedTableName:
			if src.TableName() == name {
				ret = src
			}
		}
		return ret == nil // continue until we find the matching source
	})
	return ret
}

// JoinConstraint represents either an ON or USING join constraint.
type JoinConstraint interface {
	Node
	joinConstraint()
}

func (*OnConstraint) joinConstraint()    {}
func (*UsingConstraint) joinConstraint() {}

// CloneJoinConstraint returns a deep copy cons.
func CloneJoinConstraint(cons JoinConstraint) JoinConstraint {
	if cons == nil {
		return nil
	}

	switch cons := cons.(type) {
	case *OnConstraint:
		return cons.Clone()
	case *UsingConstraint:
		return cons.Clone()
	default:
		panic(fmt.Sprintf("invalid join constraint type: %T", cons))
	}
}

type ExplainStatement struct {
	Explain   Pos       // position of EXPLAIN
	Query     Pos       // position of QUERY (optional)
	QueryPlan Pos       // position of PLAN after QUERY (optional)
	Stmt      Statement // target statement
}

// Clone returns a deep copy of s.
func (s *ExplainStatement) Clone() *ExplainStatement {
	if s == nil {
		return nil
	}
	other := *s
	other.Stmt = CloneStatement(s.Stmt)
	return &other
}

// String returns the string representation of the statement.
func (s *ExplainStatement) String() string {
	var buf bytes.Buffer
	buf.WriteString("EXPLAIN")
	if s.QueryPlan.IsValid() {
		buf.WriteString(" QUERY PLAN")
	}
	fmt.Fprintf(&buf, " %s", s.Stmt.String())
	return buf.String()
}

type BeginStatement struct {
	Begin       Pos // position of BEGIN
	Deferred    Pos // position of DEFERRED keyword
	Immediate   Pos // position of IMMEDIATE keyword
	Exclusive   Pos // position of EXCLUSIVE keyword
	Transaction Pos // position of TRANSACTION keyword  (optional)
}

// Clone returns a deep copy of s.
func (s *BeginStatement) Clone() *BeginStatement {
	if s == nil {
		return nil
	}
	other := *s
	return &other
}

// String returns the string representation of the statement.
func (s *BeginStatement) String() string {
	var buf bytes.Buffer
	buf.WriteString("BEGIN")
	if s.Deferred.IsValid() {
		buf.WriteString(" DEFERRED")
	} else if s.Immediate.IsValid() {
		buf.WriteString(" IMMEDIATE")
	} else if s.Exclusive.IsValid() {
		buf.WriteString(" EXCLUSIVE")
	}
	if s.Transaction.IsValid() {
		buf.WriteString(" TRANSACTION")
	}
	return buf.String()
}

type CommitStatement struct {
	Commit      Pos // position of COMMIT keyword
	End         Pos // position of END keyword
	Transaction Pos // position of TRANSACTION keyword  (optional)
}

// Clone returns a deep copy of s.
func (s *CommitStatement) Clone() *CommitStatement {
	if s == nil {
		return nil
	}
	other := *s
	return &other
}

// String returns the string representation of the statement.
func (s *CommitStatement) String() string {
	var buf bytes.Buffer
	if s.End.IsValid() {
		buf.WriteString("END")
	} else {
		buf.WriteString("COMMIT")
	}

	if s.Transaction.IsValid() {
		buf.WriteString(" TRANSACTION")
	}
	return buf.String()
}

type RollbackStatement struct {
	Rollback      Pos    // position of ROLLBACK keyword
	Transaction   Pos    // position of TRANSACTION keyword  (optional)
	To            Pos    // position of TO keyword  (optional)
	Savepoint     Pos    // position of SAVEPOINT keyword  (optional)
	SavepointName *Ident // name of savepoint
}

// Clone returns a deep copy of s.
func (s *RollbackStatement) Clone() *RollbackStatement {
	if s == nil {
		return s
	}
	other := *s
	other.SavepointName = s.SavepointName.Clone()
	return &other
}

// String returns the string representation of the statement.
func (s *RollbackStatement) String() string {
	var buf bytes.Buffer
	buf.WriteString("ROLLBACK")
	if s.Transaction.IsValid() {
		buf.WriteString(" TRANSACTION")
	}

	if s.SavepointName != nil {
		buf.WriteString(" TO")
		if s.Savepoint.IsValid() {
			buf.WriteString(" SAVEPOINT")
		}
		fmt.Fprintf(&buf, " %s", s.SavepointName.String())
	}
	return buf.String()
}

type SavepointStatement struct {
	Savepoint Pos    // position of SAVEPOINT keyword
	Name      *Ident // name of savepoint
}

// Clone returns a deep copy of s.
func (s *SavepointStatement) Clone() *SavepointStatement {
	if s == nil {
		return s
	}
	other := *s
	other.Name = s.Name.Clone()
	return &other
}

// String returns the string representation of the statement.
func (s *SavepointStatement) String() string {
	return fmt.Sprintf("SAVEPOINT %s", s.Name.String())
}

type ReleaseStatement struct {
	Release   Pos    // position of RELEASE keyword
	Savepoint Pos    // position of SAVEPOINT keyword (optional)
	Name      *Ident // name of savepoint
}

// Clone returns a deep copy of s.
func (s *ReleaseStatement) Clone() *ReleaseStatement {
	if s == nil {
		return s
	}
	other := *s
	other.Name = s.Name.Clone()
	return &other
}

// String returns the string representation of the statement.
func (s *ReleaseStatement) String() string {
	var buf bytes.Buffer
	buf.WriteString("RELEASE")
	if s.Savepoint.IsValid() {
		buf.WriteString(" SAVEPOINT")
	}
	fmt.Fprintf(&buf, " %s", s.Name.String())
	return buf.String()
}

type CreateTableStatement struct {
	Create      Pos    // position of CREATE keyword
	Table       Pos    // position of CREATE keyword
	If          Pos    // position of IF keyword (optional)
	IfNot       Pos    // position of NOT keyword (optional)
	IfNotExists Pos    // position of EXISTS keyword (optional)
	Name        *Ident // table name

	Lparen      Pos                 // position of left paren of column list
	Columns     []*ColumnDefinition // column definitions
	Constraints []Constraint        // table constraints
	Rparen      Pos                 // position of right paren of column list

	As     Pos              // position of AS keyword (optional)
	Select *SelectStatement // select stmt to build from
}

// Clone returns a deep copy of s.
func (s *CreateTableStatement) Clone() *CreateTableStatement {
	if s == nil {
		return s
	}
	other := *s
	other.Name = s.Name.Clone()
	other.Columns = cloneColumnDefinitions(s.Columns)
	other.Constraints = cloneConstraints(s.Constraints)
	other.Select = s.Select.Clone()
	return &other
}

// String returns the string representation of the statement.
func (s *CreateTableStatement) String() string {
	var buf bytes.Buffer
	buf.WriteString("CREATE TABLE")
	if s.IfNotExists.IsValid() {
		buf.WriteString(" IF NOT EXISTS")
	}
	buf.WriteString(" ")
	buf.WriteString(s.Name.String())

	if s.Select != nil {
		buf.WriteString(" AS ")
		buf.WriteString(s.Select.String())
	} else {
		buf.WriteString(" (")
		for i := range s.Columns {
			if i != 0 {
				buf.WriteString(", ")
			}
			buf.WriteString(s.Columns[i].String())
		}
		for i := range s.Constraints {
			buf.WriteString(", ")
			buf.WriteString(s.Constraints[i].String())
		}
		buf.WriteString(")")
	}

	return buf.String()
}

type ColumnDefinition struct {
	Name        *Ident       // column name
	Type        *Type        // data type
	Constraints []Constraint // column constraints
}

// Clone returns a deep copy of d.
func (d *ColumnDefinition) Clone() *ColumnDefinition {
	if d == nil {
		return d
	}
	other := *d
	other.Name = d.Name.Clone()
	other.Type = d.Type.Clone()
	other.Constraints = cloneConstraints(d.Constraints)
	return &other
}

func cloneColumnDefinitions(a []*ColumnDefinition) []*ColumnDefinition {
	if a == nil {
		return nil
	}
	other := make([]*ColumnDefinition, len(a))
	for i := range a {
		other[i] = a[i].Clone()
	}
	return other
}

// String returns the string representation of the statement.
func (c *ColumnDefinition) String() string {
	var buf bytes.Buffer
	buf.WriteString(c.Name.String())
	buf.WriteString(" ")
	buf.WriteString(c.Type.String())
	for i := range c.Constraints {
		buf.WriteString(" ")
		buf.WriteString(c.Constraints[i].String())
	}
	return buf.String()
}

type Constraint interface {
	Node
	constraint()
}

func (*PrimaryKeyConstraint) constraint() {}
func (*NotNullConstraint) constraint()    {}
func (*UniqueConstraint) constraint()     {}
func (*CheckConstraint) constraint()      {}
func (*DefaultConstraint) constraint()    {}
func (*ForeignKeyConstraint) constraint() {}

// CloneConstraint returns a deep copy cons.
func CloneConstraint(cons Constraint) Constraint {
	if cons == nil {
		return nil
	}

	switch cons := cons.(type) {
	case *PrimaryKeyConstraint:
		return cons.Clone()
	case *NotNullConstraint:
		return cons.Clone()
	case *UniqueConstraint:
		return cons.Clone()
	case *CheckConstraint:
		return cons.Clone()
	case *DefaultConstraint:
		return cons.Clone()
	case *ForeignKeyConstraint:
		return cons.Clone()
	default:
		panic(fmt.Sprintf("invalid constraint type: %T", cons))
	}
}

func cloneConstraints(a []Constraint) []Constraint {
	if a == nil {
		return nil
	}
	other := make([]Constraint, len(a))
	for i := range a {
		other[i] = CloneConstraint(a[i])
	}
	return other
}

type PrimaryKeyConstraint struct {
	Constraint Pos    // position of CONSTRAINT keyword
	Name       *Ident // constraint name
	Primary    Pos    // position of PRIMARY keyword
	Key        Pos    // position of KEY keyword

	Lparen  Pos      // position of left paren (table only)
	Columns []*Ident // indexed columns (table only)
	Rparen  Pos      // position of right paren (table only)

	Autoincrement Pos // position of AUTOINCREMENT keyword (column only)
}

// Clone returns a deep copy of c.
func (c *PrimaryKeyConstraint) Clone() *PrimaryKeyConstraint {
	if c == nil {
		return c
	}
	other := *c
	other.Name = c.Name.Clone()
	other.Columns = cloneIdents(c.Columns)
	return &other
}

// String returns the string representation of the constraint.
func (c *PrimaryKeyConstraint) String() string {
	var buf bytes.Buffer
	if c.Name != nil {
		buf.WriteString("CONSTRAINT ")
		buf.WriteString(c.Name.String())
		buf.WriteString(" ")
	}

	buf.WriteString("PRIMARY KEY")

	if len(c.Columns) > 0 {
		buf.WriteString(" (")
		for i := range c.Columns {
			if i != 0 {
				buf.WriteString(", ")
			}
			buf.WriteString(c.Columns[i].String())
		}
		buf.WriteString(")")
	}

	if c.Autoincrement.IsValid() {
		buf.WriteString(" AUTOINCREMENT")
	}
	return buf.String()
}

type NotNullConstraint struct {
	Constraint Pos    // position of CONSTRAINT keyword
	Name       *Ident // constraint name
	Not        Pos    // position of NOT keyword
	Null       Pos    // position of NULL keyword
}

// Clone returns a deep copy of c.
func (c *NotNullConstraint) Clone() *NotNullConstraint {
	if c == nil {
		return c
	}
	other := *c
	other.Name = c.Name.Clone()
	return &other
}

// String returns the string representation of the constraint.
func (c *NotNullConstraint) String() string {
	var buf bytes.Buffer
	if c.Name != nil {
		buf.WriteString("CONSTRAINT ")
		buf.WriteString(c.Name.String())
		buf.WriteString(" ")
	}

	buf.WriteString("NOT NULL")

	return buf.String()
}

type UniqueConstraint struct {
	Constraint Pos    // position of CONSTRAINT keyword
	Name       *Ident // constraint name
	Unique     Pos    // position of UNIQUE keyword

	Lparen  Pos      // position of left paren (table only)
	Columns []*Ident // indexed columns (table only)
	Rparen  Pos      // position of right paren (table only)
}

// Clone returns a deep copy of c.
func (c *UniqueConstraint) Clone() *UniqueConstraint {
	if c == nil {
		return c
	}
	other := *c
	other.Name = c.Name.Clone()
	other.Columns = cloneIdents(c.Columns)
	return &other
}

// String returns the string representation of the constraint.
func (c *UniqueConstraint) String() string {
	var buf bytes.Buffer
	if c.Name != nil {
		buf.WriteString("CONSTRAINT ")
		buf.WriteString(c.Name.String())
		buf.WriteString(" ")
	}

	buf.WriteString("UNIQUE")

	if len(c.Columns) > 0 {
		buf.WriteString(" (")
		for i := range c.Columns {
			if i != 0 {
				buf.WriteString(", ")
			}
			buf.WriteString(c.Columns[i].String())
		}
		buf.WriteString(")")
	}

	return buf.String()
}

type CheckConstraint struct {
	Constraint Pos    // position of CONSTRAINT keyword
	Name       *Ident // constraint name
	Check      Pos    // position of UNIQUE keyword
	Lparen     Pos    // position of left paren
	Expr       Expr   // check expression
	Rparen     Pos    // position of right paren
}

// Clone returns a deep copy of c.
func (c *CheckConstraint) Clone() *CheckConstraint {
	if c == nil {
		return c
	}
	other := *c
	other.Name = c.Name.Clone()
	other.Expr = CloneExpr(c.Expr)
	return &other
}

// String returns the string representation of the constraint.
func (c *CheckConstraint) String() string {
	var buf bytes.Buffer
	if c.Name != nil {
		buf.WriteString("CONSTRAINT ")
		buf.WriteString(c.Name.String())
		buf.WriteString(" ")
	}

	buf.WriteString("CHECK (")
	buf.WriteString(c.Expr.String())
	buf.WriteString(")")
	return buf.String()
}

type DefaultConstraint struct {
	Constraint Pos    // position of CONSTRAINT keyword
	Name       *Ident // constraint name
	Default    Pos    // position of DEFAULT keyword
	Lparen     Pos    // position of left paren
	Expr       Expr   // default expression
	Rparen     Pos    // position of right paren
}

// Clone returns a deep copy of c.
func (c *DefaultConstraint) Clone() *DefaultConstraint {
	if c == nil {
		return c
	}
	other := *c
	other.Name = c.Name.Clone()
	other.Expr = CloneExpr(c.Expr)
	return &other
}

// String returns the string representation of the constraint.
func (c *DefaultConstraint) String() string {
	var buf bytes.Buffer
	if c.Name != nil {
		buf.WriteString("CONSTRAINT ")
		buf.WriteString(c.Name.String())
		buf.WriteString(" ")
	}

	buf.WriteString("DEFAULT ")

	if c.Lparen.IsValid() {
		buf.WriteString("(")
		buf.WriteString(c.Expr.String())
		buf.WriteString(")")
	} else {
		buf.WriteString(c.Expr.String())
	}
	return buf.String()
}

type ForeignKeyConstraint struct {
	Constraint Pos    // position of CONSTRAINT keyword
	Name       *Ident // constraint name

	Foreign    Pos      // position of FOREIGN keyword (table only)
	ForeignKey Pos      // position of KEY keyword after FOREIGN (table only)
	Lparen     Pos      // position of left paren (table only)
	Columns    []*Ident // indexed columns (table only)
	Rparen     Pos      // position of right paren (table only)

	References         Pos              // position of REFERENCES keyword
	ForeignTable       *Ident           // foreign table name
	ForeignLparen      Pos              // position of left paren
	ForeignColumns     []*Ident         // column list
	ForeignRparen      Pos              // position of right paren
	Args               []*ForeignKeyArg // arguments
	Deferrable         Pos              // position of DEFERRABLE keyword
	Not                Pos              // position of NOT keyword
	NotDeferrable      Pos              // position of DEFERRABLE keyword after NOT
	Initially          Pos              // position of INITIALLY keyword
	InitiallyDeferred  Pos              // position of DEFERRED keyword after INITIALLY
	InitiallyImmediate Pos              // position of IMMEDIATE keyword after INITIALLY
}

// Clone returns a deep copy of c.
func (c *ForeignKeyConstraint) Clone() *ForeignKeyConstraint {
	if c == nil {
		return c
	}
	other := *c
	other.Name = c.Name.Clone()
	other.Columns = cloneIdents(c.Columns)
	other.ForeignTable = c.ForeignTable.Clone()
	other.ForeignColumns = cloneIdents(c.ForeignColumns)
	other.Args = cloneForeignKeyArgs(c.Args)
	return &other
}

// String returns the string representation of the constraint.
func (c *ForeignKeyConstraint) String() string {
	var buf bytes.Buffer
	if c.Name != nil {
		buf.WriteString("CONSTRAINT ")
		buf.WriteString(c.Name.String())
		buf.WriteString(" ")
	}

	if len(c.Columns) > 0 {
		buf.WriteString("FOREIGN KEY (")
		for i := range c.Columns {
			if i != 0 {
				buf.WriteString(", ")
			}
			buf.WriteString(c.Columns[i].String())
		}
		buf.WriteString(") ")
	}

	buf.WriteString("REFERENCES ")
	buf.WriteString(c.ForeignTable.String())
	if len(c.ForeignColumns) > 0 {
		buf.WriteString(" (")
		for i := range c.ForeignColumns {
			if i != 0 {
				buf.WriteString(", ")
			}
			buf.WriteString(c.ForeignColumns[i].String())
		}
		buf.WriteString(")")
	}

	for i := range c.Args {
		buf.WriteString(" ")
		buf.WriteString(c.Args[i].String())
	}

	if c.Deferrable.IsValid() || c.NotDeferrable.IsValid() {
		if c.Deferrable.IsValid() {
			buf.WriteString(" DEFERRABLE")
		} else {
			buf.WriteString(" NOT DEFERRABLE")
		}

		if c.InitiallyDeferred.IsValid() {
			buf.WriteString(" INITIALLY DEFERRED")
		} else if c.InitiallyImmediate.IsValid() {
			buf.WriteString(" INITIALLY IMMEDIATE")
		}
	}

	return buf.String()
}

type ForeignKeyArg struct {
	On         Pos // position of ON keyword
	OnUpdate   Pos // position of the UPDATE keyword
	OnDelete   Pos // position of the DELETE keyword
	Set        Pos // position of the SET keyword
	SetNull    Pos // position of the NULL keyword after SET
	SetDefault Pos // position of the DEFAULT keyword after SET
	Cascade    Pos // position of the CASCADE keyword
	Restrict   Pos // position of the RESTRICT keyword
	No         Pos // position of the NO keyword
	NoAction   Pos // position of the ACTION keyword after NO
}

// Clone returns a deep copy of arg.
func (arg *ForeignKeyArg) Clone() *ForeignKeyArg {
	if arg == nil {
		return nil
	}
	other := *arg
	return &other
}

func cloneForeignKeyArgs(a []*ForeignKeyArg) []*ForeignKeyArg {
	if a == nil {
		return nil
	}
	other := make([]*ForeignKeyArg, len(a))
	for i := range a {
		other[i] = a[i].Clone()
	}
	return other
}

// String returns the string representation of the argument.
func (c *ForeignKeyArg) String() string {
	var buf bytes.Buffer
	buf.WriteString("ON")
	if c.OnUpdate.IsValid() {
		buf.WriteString(" UPDATE")
	} else {
		buf.WriteString(" DELETE")
	}

	if c.SetNull.IsValid() {
		buf.WriteString(" SET NULL")
	} else if c.SetDefault.IsValid() {
		buf.WriteString(" SET DEFAULT")
	} else if c.Cascade.IsValid() {
		buf.WriteString(" CASCADE")
	} else if c.Restrict.IsValid() {
		buf.WriteString(" RESTRICT")
	} else if c.NoAction.IsValid() {
		buf.WriteString(" NO ACTION")
	}
	return buf.String()
}

type AnalyzeStatement struct {
	Analyze Pos    // position of ANALYZE keyword
	Name    *Ident // table name
}

// Clone returns a deep copy of s.
func (s *AnalyzeStatement) Clone() *AnalyzeStatement {
	if s == nil {
		return nil
	}
	other := *s
	other.Name = s.Name.Clone()
	return &other
}

// String returns the string representation of the statement.
func (s *AnalyzeStatement) String() string {
	return fmt.Sprintf("ANALYZE %s", s.Name.String())
}

type AlterTableStatement struct {
	Alter Pos    // position of ALTER keyword
	Table Pos    // position of TABLE keyword
	Name  *Ident // table name

	Rename   Pos    // position of RENAME keyword
	RenameTo Pos    // position of TO keyword after RENAME
	NewName  *Ident // new table name

	RenameColumn  Pos    // position of COLUMN keyword after RENAME
	ColumnName    *Ident // new column name
	To            Pos    // position of TO keyword
	NewColumnName *Ident // new column name

	Add       Pos               // position of ADD keyword
	AddColumn Pos               // position of COLUMN keyword after ADD
	ColumnDef *ColumnDefinition // new column definition
}

// Clone returns a deep copy of s.
func (s *AlterTableStatement) Clone() *AlterTableStatement {
	if s == nil {
		return nil
	}
	other := *s
	other.Name = other.Name.Clone()
	other.NewName = s.NewName.Clone()
	other.ColumnName = s.ColumnName.Clone()
	other.NewColumnName = s.NewColumnName.Clone()
	other.ColumnDef = s.ColumnDef.Clone()
	return &other
}

// String returns the string representation of the statement.
func (s *AlterTableStatement) String() string {
	var buf bytes.Buffer
	buf.WriteString("ALTER TABLE ")
	buf.WriteString(s.Name.String())

	if s.NewName != nil {
		buf.WriteString(" RENAME TO ")
		buf.WriteString(s.NewName.String())
	} else if s.ColumnName != nil {
		buf.WriteString(" RENAME COLUMN ")
		buf.WriteString(s.ColumnName.String())
		buf.WriteString(" TO ")
		buf.WriteString(s.NewColumnName.String())
	} else if s.ColumnDef != nil {
		buf.WriteString(" ADD COLUMN ")
		buf.WriteString(s.ColumnDef.String())
	}

	return buf.String()
}

type Ident struct {
	NamePos Pos    // identifier position
	Name    string // identifier name
	Quoted  bool   // true if double quoted
}

// IsAggregate returns false.
func (expr *Ident) IsAggregate() bool { return false }

// Clone returns a deep copy of i.
func (i *Ident) Clone() *Ident {
	if i == nil {
		return nil
	}
	other := *i
	return &other
}

func cloneIdents(a []*Ident) []*Ident {
	if a == nil {
		return nil
	}
	other := make([]*Ident, len(a))
	for i := range a {
		other[i] = a[i].Clone()
	}
	return other
}

// String returns the string representation of the expression.
func (i *Ident) String() string {
	return `"` + strings.Replace(i.Name, `"`, `""`, -1) + `"`
}

// IdentName returns the name of ident. Returns a blank string if ident is nil.
func IdentName(ident *Ident) string {
	if ident == nil {
		return ""
	}
	return ident.Name
}

type Type struct {
	Name      *Ident     // type name
	Lparen    Pos        // position of left paren (optional)
	Precision *NumberLit // precision (optional)
	Scale     *NumberLit // scale (optional)
	Rparen    Pos        // position of right paren (optional)
}

// Clone returns a deep copy of t.
func (t *Type) Clone() *Type {
	if t == nil {
		return nil
	}
	other := *t
	other.Name = t.Name.Clone()
	other.Precision = t.Precision.Clone()
	other.Scale = t.Scale.Clone()
	return &other
}

// String returns the string representation of the type.
func (t *Type) String() string {
	if t.Precision != nil && t.Scale != nil {
		return fmt.Sprintf("%s(%s,%s)", t.Name.Name, t.Precision.String(), t.Scale.String())
	} else if t.Precision != nil {
		return fmt.Sprintf("%s(%s)", t.Name.Name, t.Precision.String())
	}
	return t.Name.Name
}

type StringLit struct {
	ValuePos Pos    // literal position
	Value    string // literal value (without quotes)
}

// IsAggregate returns false.
func (expr *StringLit) IsAggregate() bool { return false }

// Clone returns a deep copy of lit.
func (lit *StringLit) Clone() *StringLit {
	if lit == nil {
		return nil
	}
	other := *lit
	return &other
}

// String returns the string representation of the expression.
func (lit *StringLit) String() string {
	return `'` + strings.Replace(lit.Value, `'`, `''`, -1) + `'`
}

type BlobLit struct {
	ValuePos Pos    // literal position
	Value    string // literal value
}

// IsAggregate returns false.
func (expr *BlobLit) IsAggregate() bool { return false }

// Clone returns a deep copy of lit.
func (lit *BlobLit) Clone() *BlobLit {
	if lit == nil {
		return nil
	}
	other := *lit
	return &other
}

// String returns the string representation of the expression.
func (lit *BlobLit) String() string {
	return `x'` + lit.Value + `'`
}

type NumberLit struct {
	ValuePos Pos    // literal position
	Value    string // literal value
}

// IsAggregate returns false.
func (expr *NumberLit) IsAggregate() bool { return false }

// IsFloat returns true if literal contains a dot or 'e'.
func (expr *NumberLit) IsFloat() bool {
	return strings.Contains(expr.Value, ".") ||
		strings.Contains(expr.Value, "e") ||
		strings.Contains(expr.Value, "E")
}

// Clone returns a deep copy of lit.
func (lit *NumberLit) Clone() *NumberLit {
	if lit == nil {
		return nil
	}
	other := *lit
	return &other
}

// String returns the string representation of the expression.
func (lit *NumberLit) String() string {
	return lit.Value
}

type NullLit struct {
	Pos Pos
}

// IsAggregate returns false.
func (expr *NullLit) IsAggregate() bool { return false }

// Clone returns a deep copy of lit.
func (lit *NullLit) Clone() *NullLit {
	if lit == nil {
		return nil
	}
	other := *lit
	return &other
}

// String returns the string representation of the expression.
func (lit *NullLit) String() string {
	return "NULL"
}

type BoolLit struct {
	ValuePos Pos  // literal position
	Value    bool // literal value
}

// IsAggregate returns false.
func (expr *BoolLit) IsAggregate() bool { return false }

// Clone returns a deep copy of lit.
func (lit *BoolLit) Clone() *BoolLit {
	if lit == nil {
		return nil
	}
	other := *lit
	return &other
}

// String returns the string representation of the expression.
func (lit *BoolLit) String() string {
	if lit.Value {
		return "TRUE"
	}
	return "FALSE"
}

type BindExpr struct {
	NamePos Pos    // name position
	Name    string // binding name
}

// IsAggregate returns false.
func (expr *BindExpr) IsAggregate() bool { return false }

// Clone returns a deep copy of expr.
func (expr *BindExpr) Clone() *BindExpr {
	if expr == nil {
		return nil
	}
	other := *expr
	return &other
}

// String returns the string representation of the expression.
func (expr *BindExpr) String() string {
	// TODO(BBJ): Support all bind characters.
	return "$" + expr.Name
}

type UnaryExpr struct {
	OpPos Pos   // operation position
	Op    Token // operation
	X     Expr  // target expression
}

// IsAggregate returns true if it contains an aggregate call.
func (expr *UnaryExpr) IsAggregate() bool {
	return expr.X.IsAggregate()
}

// Clone returns a deep copy of expr.
func (expr *UnaryExpr) Clone() *UnaryExpr {
	if expr == nil {
		return nil
	}
	other := *expr
	other.X = CloneExpr(expr.X)
	return &other
}

// String returns the string representation of the expression.
func (expr *UnaryExpr) String() string {
	switch expr.Op {
	case PLUS:
		return "+" + expr.X.String()
	case MINUS:
		return "-" + expr.X.String()
	default:
		panic(fmt.Sprintf("sql.UnaryExpr.String(): invalid op %s", expr.Op))
	}
}

type BinaryExpr struct {
	X     Expr  // lhs
	OpPos Pos   // position of Op
	Op    Token // operator
	Y     Expr  // rhs
}

// IsAggregate returns true if it contains an aggregate call.
func (expr *BinaryExpr) IsAggregate() bool {
	if expr.X.IsAggregate() {
		return true
	}
	return expr.Y.IsAggregate()
}

// Clone returns a deep copy of expr.
func (expr *BinaryExpr) Clone() *BinaryExpr {
	if expr == nil {
		return nil
	}
	other := *expr
	other.X = CloneExpr(expr.X)
	other.Y = CloneExpr(expr.Y)
	return &other
}

// String returns the string representation of the expression.
func (expr *BinaryExpr) String() string {
	switch expr.Op {
	case PLUS:
		return expr.X.String() + " + " + expr.Y.String()
	case MINUS:
		return expr.X.String() + " - " + expr.Y.String()
	case STAR:
		return expr.X.String() + " * " + expr.Y.String()
	case SLASH:
		return expr.X.String() + " / " + expr.Y.String()
	case REM:
		return expr.X.String() + " % " + expr.Y.String()
	case CONCAT:
		return expr.X.String() + " || " + expr.Y.String()
	case BETWEEN:
		return expr.X.String() + " BETWEEN " + expr.Y.String()
	case NOTBETWEEN:
		return expr.X.String() + " NOT BETWEEN " + expr.Y.String()
	case LSHIFT:
		return expr.X.String() + " << " + expr.Y.String()
	case RSHIFT:
		return expr.X.String() + " >> " + expr.Y.String()
	case BITAND:
		return expr.X.String() + " & " + expr.Y.String()
	case BITOR:
		return expr.X.String() + " | " + expr.Y.String()
	case LT:
		return expr.X.String() + " < " + expr.Y.String()
	case LE:
		return expr.X.String() + " <= " + expr.Y.String()
	case GT:
		return expr.X.String() + " > " + expr.Y.String()
	case GE:
		return expr.X.String() + " >= " + expr.Y.String()
	case EQ:
		return expr.X.String() + " = " + expr.Y.String()
	case NE:
		return expr.X.String() + " != " + expr.Y.String()
	case IS:
		return expr.X.String() + " IS " + expr.Y.String()
	case ISNOT:
		return expr.X.String() + " IS NOT " + expr.Y.String()
	case IN:
		return expr.X.String() + " IN " + expr.Y.String()
	case NOTIN:
		return expr.X.String() + " NOT IN " + expr.Y.String()
	case LIKE:
		return expr.X.String() + " LIKE " + expr.Y.String()
	case NOTLIKE:
		return expr.X.String() + " NOT LIKE " + expr.Y.String()
	case GLOB:
		return expr.X.String() + " GLOB " + expr.Y.String()
	case NOTGLOB:
		return expr.X.String() + " NOT GLOB " + expr.Y.String()
	case MATCH:
		return expr.X.String() + " MATCH " + expr.Y.String()
	case NOTMATCH:
		return expr.X.String() + " NOT MATCH " + expr.Y.String()
	case REGEXP:
		return expr.X.String() + " REGEXP " + expr.Y.String()
	case NOTREGEXP:
		return expr.X.String() + " NOT REGEXP " + expr.Y.String()
	case AND:
		return expr.X.String() + " AND " + expr.Y.String()
	case OR:
		return expr.X.String() + " OR " + expr.Y.String()
	default:
		panic(fmt.Sprintf("sql.BinaryExpr.String(): invalid op %s", expr.Op))
	}
}

type CastExpr struct {
	Cast   Pos   // position of CAST keyword
	Lparen Pos   // position of left paren
	X      Expr  // target expression
	As     Pos   // position of AS keyword
	Type   *Type // cast type
	Rparen Pos   // position of right paren
}

// IsAggregate returns true if it contains an aggregate call.
func (expr *CastExpr) IsAggregate() bool {
	return expr.X.IsAggregate()
}

// Clone returns a deep copy of expr.
func (expr *CastExpr) Clone() *CastExpr {
	if expr == nil {
		return nil
	}
	other := *expr
	other.X = CloneExpr(expr.X)
	other.Type = expr.Type.Clone()
	return &other
}

// String returns the string representation of the expression.
func (expr *CastExpr) String() string {
	return fmt.Sprintf("CAST(%s AS %s)", expr.X.String(), expr.Type.String())
}

type CaseExpr struct {
	Case     Pos          // position of CASE keyword
	Operand  Expr         // optional condition after the CASE keyword
	Blocks   []*CaseBlock // list of WHEN/THEN pairs
	Else     Pos          // position of ELSE keyword
	ElseExpr Expr         // expression used by default case
	End      Pos          // position of END keyword
}

// IsAggregate returns false
func (expr *CaseExpr) IsAggregate() bool { return false }

// Clone returns a deep copy of expr.
func (expr *CaseExpr) Clone() *CaseExpr {
	if expr == nil {
		return nil
	}
	other := *expr
	other.Operand = CloneExpr(expr.Operand)
	other.Blocks = cloneCaseBlocks(expr.Blocks)
	other.ElseExpr = CloneExpr(expr.ElseExpr)
	return &other
}

// String returns the string representation of the expression.
func (expr *CaseExpr) String() string {
	var buf bytes.Buffer
	buf.WriteString("CASE")
	if expr.Operand != nil {
		buf.WriteString(" ")
		buf.WriteString(expr.Operand.String())
	}
	for _, blk := range expr.Blocks {
		buf.WriteString(" ")
		buf.WriteString(blk.String())
	}
	if expr.ElseExpr != nil {
		buf.WriteString(" ELSE ")
		buf.WriteString(expr.ElseExpr.String())
	}
	buf.WriteString(" END")
	return buf.String()
}

type CaseBlock struct {
	When      Pos  // position of WHEN keyword
	Condition Expr // block condition
	Then      Pos  // position of THEN keyword
	Body      Expr // result expression
}

// Clone returns a deep copy of blk.
func (blk *CaseBlock) Clone() *CaseBlock {
	if blk == nil {
		return nil
	}
	other := *blk
	other.Condition = CloneExpr(blk.Condition)
	other.Body = CloneExpr(blk.Body)
	return &other
}

func cloneCaseBlocks(a []*CaseBlock) []*CaseBlock {
	if a == nil {
		return nil
	}
	other := make([]*CaseBlock, len(a))
	for i := range a {
		other[i] = a[i].Clone()
	}
	return other
}

// String returns the string representation of the block.
func (b *CaseBlock) String() string {
	return fmt.Sprintf("WHEN %s THEN %s", b.Condition.String(), b.Body.String())
}

type Raise struct {
	Raise    Pos        // position of RAISE keyword
	Lparen   Pos        // position of left paren
	Ignore   Pos        // position of IGNORE keyword
	Rollback Pos        // position of ROLLBACK keyword
	Abort    Pos        // position of ABORT keyword
	Fail     Pos        // position of FAIL keyword
	Comma    Pos        // position of comma
	Error    *StringLit // error message
	Rparen   Pos        // position of right paren
}

// IsAggregate returns false.
func (expr *Raise) IsAggregate() bool { return false }

// Clone returns a deep copy of r.
func (r *Raise) Clone() *Raise {
	if r == nil {
		return nil
	}
	other := *r
	other.Error = r.Error.Clone()
	return &other
}

// String returns the string representation of the raise function.
func (r *Raise) String() string {
	var buf bytes.Buffer
	buf.WriteString("RAISE(")
	if r.Rollback.IsValid() {
		fmt.Fprintf(&buf, "ROLLBACK, %s", r.Error.String())
	} else if r.Abort.IsValid() {
		fmt.Fprintf(&buf, "ABORT, %s", r.Error.String())
	} else if r.Fail.IsValid() {
		fmt.Fprintf(&buf, "FAIL, %s", r.Error.String())
	} else {
		buf.WriteString("IGNORE")
	}
	buf.WriteString(")")
	return buf.String()
}

type Exists struct {
	Not    Pos              // position of optional NOT keyword
	Exists Pos              // position of EXISTS keyword
	Lparen Pos              // position of left paren
	Select *SelectStatement // select statement
	Rparen Pos              // position of right paren
}

// IsAggregate returns false.
func (expr *Exists) IsAggregate() bool { return false }

// Clone returns a deep copy of expr.
func (expr *Exists) Clone() *Exists {
	if expr == nil {
		return nil
	}
	other := *expr
	other.Select = expr.Select.Clone()
	return &other
}

// String returns the string representation of the expression.
func (expr *Exists) String() string {
	if expr.Not.IsValid() {
		return fmt.Sprintf("NOT EXISTS (%s)", expr.Select.String())
	}
	return fmt.Sprintf("EXISTS (%s)", expr.Select.String())
}

type ExprList struct {
	Lparen Pos    // position of left paren
	Exprs  []Expr // list of expressions
	Rparen Pos    // position of right paren
}

// IsAggregate returns true if any child expression is an aggregate.
func (expr *ExprList) IsAggregate() bool {
	for _, e := range expr.Exprs {
		if e.IsAggregate() {
			return true
		}
	}
	return false
}

// Clone returns a deep copy of l.
func (l *ExprList) Clone() *ExprList {
	if l == nil {
		return nil
	}
	other := *l
	other.Exprs = cloneExprs(l.Exprs)
	return &other
}

func cloneExprLists(a []*ExprList) []*ExprList {
	if a == nil {
		return nil
	}
	other := make([]*ExprList, len(a))
	for i := range a {
		other[i] = a[i].Clone()
	}
	return other
}

// String returns the string representation of the expression.
func (l *ExprList) String() string {
	var buf bytes.Buffer
	buf.WriteString("(")
	for i, expr := range l.Exprs {
		if i != 0 {
			buf.WriteString(", ")
		}
		buf.WriteString(expr.String())
	}
	buf.WriteString(")")
	return buf.String()
}

type Range struct {
	X   Expr // lhs expression
	And Pos  // position of AND keyword
	Y   Expr // rhs expression
}

// IsAggregate returns false.
func (expr *Range) IsAggregate() bool { return false }

// Clone returns a deep copy of r.
func (r *Range) Clone() *Range {
	if r == nil {
		return nil
	}
	other := *r
	other.X = CloneExpr(r.X)
	other.Y = CloneExpr(r.Y)
	return &other
}

// String returns the string representation of the expression.
func (r *Range) String() string {
	return fmt.Sprintf("%s AND %s", r.X.String(), r.Y.String())
}

type QualifiedRef struct {
	Table  *Ident // table name
	Dot    Pos    // position of dot
	Star   Pos    // position of * (result column only)
	Column *Ident // column name

	// Set by the planner; not at parse-time
	DataType string
}

// IsAggregate returns false.
func (expr *QualifiedRef) IsAggregate() bool { return false }

// Clone returns a deep copy of r.
func (r *QualifiedRef) Clone() *QualifiedRef {
	if r == nil {
		return nil
	}
	other := *r
	other.Table = r.Table.Clone()
	other.Column = r.Column.Clone()
	return &other
}

// String returns the string representation of the expression.
func (r *QualifiedRef) String() string {
	if r.Star.IsValid() {
		return fmt.Sprintf("%s.*", r.Table.String())
	}
	return fmt.Sprintf("%s.%s", r.Table.String(), r.Column.String())
}

type Call struct {
	Name     *Ident        // function name
	Lparen   Pos           // position of left paren
	Star     Pos           // position of *
	Distinct Pos           // position of DISTINCT keyword
	Args     []Expr        // argument list
	Rparen   Pos           // position of right paren
	Filter   *FilterClause // filter clause
	Over     *OverClause   // over clause
}

// IsAggregate returns true if call is an aggregate function or it contains one.
func (expr *Call) IsAggregate() bool {
	// Check if this is an aggregate call.
	switch strings.ToUpper(IdentName(expr.Name)) {
	case "COUNT", "MIN", "MAX", "SUM":
		return true
	}

	// Check if any arguments to the call are aggregate.
	for _, arg := range expr.Args {
		if arg.IsAggregate() {
			return true
		}
	}
	return false
}

// Clone returns a deep copy of c.
func (c *Call) Clone() *Call {
	if c == nil {
		return nil
	}
	other := *c
	other.Name = c.Name.Clone()
	other.Args = cloneExprs(c.Args)
	other.Filter = c.Filter.Clone()
	other.Over = c.Over.Clone()
	return &other
}

// String returns the string representation of the expression.
func (c *Call) String() string {
	var buf bytes.Buffer
	buf.WriteString(c.Name.Name)
	buf.WriteString("(")
	if c.Star.IsValid() {
		buf.WriteString("*")
	} else {
		if c.Distinct.IsValid() {
			buf.WriteString("DISTINCT")
			if len(c.Args) != 0 {
				buf.WriteString(" ")
			}
		}
		for i, arg := range c.Args {
			if i != 0 {
				buf.WriteString(", ")
			}
			buf.WriteString(arg.String())
		}
	}
	buf.WriteString(")")

	if c.Filter != nil {
		buf.WriteString(" ")
		buf.WriteString(c.Filter.String())
	}

	if c.Over != nil {
		buf.WriteString(" ")
		buf.WriteString(c.Over.String())
	}

	return buf.String()
}

type FilterClause struct {
	Filter Pos  // position of FILTER keyword
	Lparen Pos  // position of left paren
	Where  Pos  // position of WHERE keyword
	X      Expr // filter expression
	Rparen Pos  // position of right paren
}

// Clone returns a deep copy of c.
func (c *FilterClause) Clone() *FilterClause {
	if c == nil {
		return nil
	}
	other := *c
	other.X = CloneExpr(c.X)
	return &other
}

// String returns the string representation of the clause.
func (c *FilterClause) String() string {
	return fmt.Sprintf("FILTER (WHERE %s)", c.X.String())
}

type OverClause struct {
	Over       Pos               // position of OVER keyword
	Name       *Ident            // window name
	Definition *WindowDefinition // window definition
}

// Clone returns a deep copy of c.
func (c *OverClause) Clone() *OverClause {
	if c == nil {
		return nil
	}
	other := *c
	other.Name = c.Name.Clone()
	other.Definition = c.Definition.Clone()
	return &other
}

// String returns the string representation of the clause.
func (c *OverClause) String() string {
	if c.Name != nil {
		return fmt.Sprintf("OVER %s", c.Name.String())
	}
	return fmt.Sprintf("OVER %s", c.Definition.String())
}

type OrderingTerm struct {
	X Expr // ordering expression

	Asc  Pos // position of ASC keyword
	Desc Pos // position of DESC keyword

	Nulls      Pos // position of NULLS keyword
	NullsFirst Pos // position of FIRST keyword
	NullsLast  Pos // position of LAST keyword
}

// Clone returns a deep copy of t.
func (t *OrderingTerm) Clone() *OrderingTerm {
	if t == nil {
		return nil
	}
	other := *t
	other.X = CloneExpr(t.X)
	return &other
}

func cloneOrderingTerms(a []*OrderingTerm) []*OrderingTerm {
	if a == nil {
		return nil
	}
	other := make([]*OrderingTerm, len(a))
	for i := range a {
		other[i] = a[i].Clone()
	}
	return other
}

// String returns the string representation of the term.
func (t *OrderingTerm) String() string {
	var buf bytes.Buffer
	buf.WriteString(t.X.String())

	if t.Asc.IsValid() {
		buf.WriteString(" ASC")
	} else if t.Desc.IsValid() {
		buf.WriteString(" DESC")
	}

	if t.NullsFirst.IsValid() {
		buf.WriteString(" NULLS FIRST")
	} else if t.NullsLast.IsValid() {
		buf.WriteString(" NULLS LAST")
	}

	return buf.String()
}

type FrameSpec struct {
	Range  Pos // position of RANGE keyword
	Rows   Pos // position of ROWS keyword
	Groups Pos // position of GROUPS keyword

	Between Pos // position of BETWEEN keyword

	X           Expr // lhs expression
	UnboundedX  Pos  // position of lhs UNBOUNDED keyword
	PrecedingX  Pos  // position of lhs PRECEDING keyword
	CurrentX    Pos  // position of lhs CURRENT keyword
	CurrentRowX Pos  // position of lhs ROW keyword
	FollowingX  Pos  // position of lhs FOLLOWING keyword

	And Pos // position of AND keyword

	Y           Expr // lhs expression
	UnboundedY  Pos  // position of rhs UNBOUNDED keyword
	FollowingY  Pos  // position of rhs FOLLOWING keyword
	CurrentY    Pos  // position of rhs CURRENT keyword
	CurrentRowY Pos  // position of rhs ROW keyword
	PrecedingY  Pos  // position of rhs PRECEDING keyword

	Exclude           Pos // position of EXCLUDE keyword
	ExcludeNo         Pos // position of NO keyword after EXCLUDE
	ExcludeNoOthers   Pos // position of OTHERS keyword after EXCLUDE NO
	ExcludeCurrent    Pos // position of CURRENT keyword after EXCLUDE
	ExcludeCurrentRow Pos // position of ROW keyword after EXCLUDE CURRENT
	ExcludeGroup      Pos // position of GROUP keyword after EXCLUDE
	ExcludeTies       Pos // position of TIES keyword after EXCLUDE
}

// Clone returns a deep copy of s.
func (s *FrameSpec) Clone() *FrameSpec {
	if s == nil {
		return nil
	}
	other := *s
	other.X = CloneExpr(s.X)
	other.X = CloneExpr(s.Y)
	return &other
}

// String returns the string representation of the frame spec.
func (s *FrameSpec) String() string {
	var buf bytes.Buffer
	if s.Range.IsValid() {
		buf.WriteString("RANGE")
	} else if s.Rows.IsValid() {
		buf.WriteString("ROWS")
	} else if s.Groups.IsValid() {
		buf.WriteString("GROUPS")
	}

	if s.Between.IsValid() {
		buf.WriteString(" BETWEEN")
		if s.UnboundedX.IsValid() && s.PrecedingX.IsValid() {
			buf.WriteString(" UNBOUNDED PRECEDING")
		} else if s.X != nil && s.PrecedingX.IsValid() {
			fmt.Fprintf(&buf, " %s PRECEDING", s.X.String())
		} else if s.CurrentRowX.IsValid() {
			buf.WriteString(" CURRENT ROW")
		} else if s.X != nil && s.FollowingX.IsValid() {
			fmt.Fprintf(&buf, " %s FOLLOWING", s.X.String())
		}

		buf.WriteString(" AND")

		if s.Y != nil && s.PrecedingY.IsValid() {
			fmt.Fprintf(&buf, " %s PRECEDING", s.Y.String())
		} else if s.CurrentRowY.IsValid() {
			buf.WriteString(" CURRENT ROW")
		} else if s.Y != nil && s.FollowingY.IsValid() {
			fmt.Fprintf(&buf, " %s FOLLOWING", s.Y.String())
		} else if s.UnboundedY.IsValid() && s.FollowingY.IsValid() {
			buf.WriteString(" UNBOUNDED FOLLOWING")
		}
	} else {
		if s.UnboundedX.IsValid() && s.PrecedingX.IsValid() {
			buf.WriteString(" UNBOUNDED PRECEDING")
		} else if s.X != nil && s.PrecedingX.IsValid() {
			fmt.Fprintf(&buf, " %s PRECEDING", s.X.String())
		} else if s.CurrentRowX.IsValid() {
			buf.WriteString(" CURRENT ROW")
		}
	}

	if s.ExcludeNoOthers.IsValid() {
		buf.WriteString(" EXCLUDE NO OTHERS")
	} else if s.ExcludeCurrentRow.IsValid() {
		buf.WriteString(" EXCLUDE CURRENT ROW")
	} else if s.ExcludeGroup.IsValid() {
		buf.WriteString(" EXCLUDE GROUP")
	} else if s.ExcludeTies.IsValid() {
		buf.WriteString(" EXCLUDE TIES")
	}

	return buf.String()
}

type ColumnArg interface {
	Node
	columnArg()
}

type DropTableStatement struct {
	Drop     Pos    // position of DROP keyword
	Table    Pos    // position of TABLE keyword
	If       Pos    // position of IF keyword
	IfExists Pos    // position of EXISTS keyword after IF
	Name     *Ident // view name
}

// Clone returns a deep copy of s.
func (s *DropTableStatement) Clone() *DropTableStatement {
	if s == nil {
		return nil
	}
	other := *s
	other.Name = s.Name.Clone()
	return &other
}

// String returns the string representation of the statement.
func (s *DropTableStatement) String() string {
	var buf bytes.Buffer
	buf.WriteString("DROP TABLE")
	if s.IfExists.IsValid() {
		buf.WriteString(" IF EXISTS")
	}
	fmt.Fprintf(&buf, " %s", s.Name.String())
	return buf.String()
}

type CreateViewStatement struct {
	Create      Pos              // position of CREATE keyword
	View        Pos              // position of VIEW keyword
	If          Pos              // position of IF keyword
	IfNot       Pos              // position of NOT keyword after IF
	IfNotExists Pos              // position of EXISTS keyword after IF NOT
	Name        *Ident           // view name
	Lparen      Pos              // position of column list left paren
	Columns     []*Ident         // column list
	Rparen      Pos              // position of column list right paren
	As          Pos              // position of AS keyword
	Select      *SelectStatement // source statement
}

// Clone returns a deep copy of s.
func (s *CreateViewStatement) Clone() *CreateViewStatement {
	if s == nil {
		return nil
	}
	other := *s
	other.Name = s.Name.Clone()
	other.Columns = cloneIdents(s.Columns)
	other.Select = s.Select.Clone()
	return &other
}

// String returns the string representation of the statement.
func (s *CreateViewStatement) String() string {
	var buf bytes.Buffer
	buf.WriteString("CREATE VIEW")
	if s.IfNotExists.IsValid() {
		buf.WriteString(" IF NOT EXISTS")
	}
	fmt.Fprintf(&buf, " %s", s.Name.String())

	if len(s.Columns) > 0 {
		buf.WriteString(" (")
		for i, col := range s.Columns {
			if i != 0 {
				buf.WriteString(", ")
			}
			buf.WriteString(col.String())
		}
		buf.WriteString(")")
	}

	fmt.Fprintf(&buf, " AS %s", s.Select.String())

	return buf.String()
}

type DropViewStatement struct {
	Drop     Pos    // position of DROP keyword
	View     Pos    // position of VIEW keyword
	If       Pos    // position of IF keyword
	IfExists Pos    // position of EXISTS keyword after IF
	Name     *Ident // view name
}

// Clone returns a deep copy of s.
func (s *DropViewStatement) Clone() *DropViewStatement {
	if s == nil {
		return nil
	}
	other := *s
	other.Name = s.Name.Clone()
	return &other
}

// String returns the string representation of the statement.
func (s *DropViewStatement) String() string {
	var buf bytes.Buffer
	buf.WriteString("DROP VIEW")
	if s.IfExists.IsValid() {
		buf.WriteString(" IF EXISTS")
	}
	fmt.Fprintf(&buf, " %s", s.Name.String())
	return buf.String()
}

type CreateIndexStatement struct {
	Create      Pos              // position of CREATE keyword
	Unique      Pos              // position of optional UNIQUE keyword
	Index       Pos              // position of INDEX keyword
	If          Pos              // position of IF keyword
	IfNot       Pos              // position of NOT keyword after IF
	IfNotExists Pos              // position of EXISTS keyword after IF NOT
	Name        *Ident           // index name
	On          Pos              // position of ON keyword
	Table       *Ident           // index name
	Lparen      Pos              // position of column list left paren
	Columns     []*IndexedColumn // column list
	Rparen      Pos              // position of column list right paren
	Where       Pos              // position of WHERE keyword
	WhereExpr   Expr             // conditional expression
}

// Clone returns a deep copy of s.
func (s *CreateIndexStatement) Clone() *CreateIndexStatement {
	if s == nil {
		return nil
	}
	other := *s
	other.Name = s.Name.Clone()
	other.Table = s.Table.Clone()
	other.Columns = cloneIndexedColumns(s.Columns)
	other.WhereExpr = CloneExpr(s.WhereExpr)
	return &other
}

// String returns the string representation of the statement.
func (s *CreateIndexStatement) String() string {
	var buf bytes.Buffer
	buf.WriteString("CREATE")
	if s.Unique.IsValid() {
		buf.WriteString(" UNIQUE")
	}
	buf.WriteString(" INDEX")
	if s.IfNotExists.IsValid() {
		buf.WriteString(" IF NOT EXISTS")
	}
	fmt.Fprintf(&buf, " %s ON %s ", s.Name.String(), s.Table.String())

	buf.WriteString("(")
	for i, col := range s.Columns {
		if i != 0 {
			buf.WriteString(", ")
		}
		buf.WriteString(col.String())
	}
	buf.WriteString(")")

	if s.WhereExpr != nil {
		fmt.Fprintf(&buf, " WHERE %s", s.WhereExpr.String())
	}

	return buf.String()
}

type DropIndexStatement struct {
	Drop     Pos    // position of DROP keyword
	Index    Pos    // position of INDEX keyword
	If       Pos    // position of IF keyword
	IfExists Pos    // position of EXISTS keyword after IF
	Name     *Ident // index name
}

// Clone returns a deep copy of s.
func (s *DropIndexStatement) Clone() *DropIndexStatement {
	if s == nil {
		return nil
	}
	other := *s
	other.Name = s.Name.Clone()
	return &other
}

// String returns the string representation of the statement.
func (s *DropIndexStatement) String() string {
	var buf bytes.Buffer
	buf.WriteString("DROP INDEX")
	if s.IfExists.IsValid() {
		buf.WriteString(" IF EXISTS")
	}
	fmt.Fprintf(&buf, " %s", s.Name.String())
	return buf.String()
}

type CreateTriggerStatement struct {
	Create      Pos    // position of CREATE keyword
	Trigger     Pos    // position of TRIGGER keyword
	If          Pos    // position of IF keyword
	IfNot       Pos    // position of NOT keyword after IF
	IfNotExists Pos    // position of EXISTS keyword after IF NOT
	Name        *Ident // index name

	Before    Pos // position of BEFORE keyword
	After     Pos // position of AFTER keyword
	Instead   Pos // position of INSTEAD keyword
	InsteadOf Pos // position of OF keyword after INSTEAD

	Delete          Pos      // position of DELETE keyword
	Insert          Pos      // position of INSERT keyword
	Update          Pos      // position of UPDATE keyword
	UpdateOf        Pos      // position of OF keyword after UPDATE
	UpdateOfColumns []*Ident // columns list for UPDATE OF
	On              Pos      // position of ON keyword
	Table           *Ident   // table name

	For        Pos // position of FOR keyword
	ForEach    Pos // position of EACH keyword after FOR
	ForEachRow Pos // position of ROW keyword after FOR EACH

	When     Pos  // position of WHEN keyword
	WhenExpr Expr // conditional expression

	Begin Pos         // position of BEGIN keyword
	Body  []Statement // trigger body
	End   Pos         // position of END keyword
}

// Clone returns a deep copy of s.
func (s *CreateTriggerStatement) Clone() *CreateTriggerStatement {
	if s == nil {
		return nil
	}
	other := *s
	other.Name = s.Name.Clone()
	other.UpdateOfColumns = cloneIdents(s.UpdateOfColumns)
	other.Table = s.Table.Clone()
	other.WhenExpr = CloneExpr(s.WhenExpr)
	other.Body = cloneStatements(s.Body)
	return &other
}

// String returns the string representation of the statement.
func (s *CreateTriggerStatement) String() string {
	var buf bytes.Buffer
	buf.WriteString("CREATE TRIGGER")
	if s.IfNotExists.IsValid() {
		buf.WriteString(" IF NOT EXISTS")
	}
	fmt.Fprintf(&buf, " %s", s.Name.String())

	if s.Before.IsValid() {
		buf.WriteString(" BEFORE")
	} else if s.After.IsValid() {
		buf.WriteString(" AFTER")
	} else if s.InsteadOf.IsValid() {
		buf.WriteString(" INSTEAD OF")
	}

	if s.Delete.IsValid() {
		buf.WriteString(" DELETE")
	} else if s.Insert.IsValid() {
		buf.WriteString(" INSERT")
	} else if s.Update.IsValid() {
		buf.WriteString(" UPDATE")
		if s.UpdateOf.IsValid() {
			buf.WriteString(" OF ")
			for i, col := range s.UpdateOfColumns {
				if i != 0 {
					buf.WriteString(", ")
				}
				buf.WriteString(col.String())
			}
		}
	}

	fmt.Fprintf(&buf, " ON %s", s.Table.String())

	if s.ForEachRow.IsValid() {
		buf.WriteString(" FOR EACH ROW")
	}

	if s.WhenExpr != nil {
		fmt.Fprintf(&buf, " WHEN %s", s.WhenExpr.String())
	}

	buf.WriteString(" BEGIN")
	for i := range s.Body {
		fmt.Fprintf(&buf, " %s;", s.Body[i].String())
	}
	buf.WriteString(" END")

	return buf.String()
}

type DropTriggerStatement struct {
	Drop     Pos    // position of DROP keyword
	Trigger  Pos    // position of TRIGGER keyword
	If       Pos    // position of IF keyword
	IfExists Pos    // position of EXISTS keyword after IF
	Name     *Ident // trigger name
}

// Clone returns a deep copy of s.
func (s *DropTriggerStatement) Clone() *DropTriggerStatement {
	if s == nil {
		return nil
	}
	other := *s
	other.Name = s.Name.Clone()
	return &other
}

// String returns the string representation of the statement.
func (s *DropTriggerStatement) String() string {
	var buf bytes.Buffer
	buf.WriteString("DROP TRIGGER")
	if s.IfExists.IsValid() {
		buf.WriteString(" IF EXISTS")
	}
	fmt.Fprintf(&buf, " %s", s.Name.String())
	return buf.String()
}

type InsertStatement struct {
	WithClause *WithClause // clause containing CTEs

	Insert           Pos // position of INSERT keyword
	Replace          Pos // position of REPLACE keyword
	InsertOr         Pos // position of OR keyword after INSERT
	InsertOrReplace  Pos // position of REPLACE keyword after INSERT OR
	InsertOrRollback Pos // position of ROLLBACK keyword after INSERT OR
	InsertOrAbort    Pos // position of ABORT keyword after INSERT OR
	InsertOrFail     Pos // position of FAIL keyword after INSERT OR
	InsertOrIgnore   Pos // position of IGNORE keyword after INSERT OR
	Into             Pos // position of INTO keyword

	Table *Ident // table name
	As    Pos    // position of AS keyword
	Alias *Ident // optional alias

	ColumnsLparen Pos      // position of column list left paren
	Columns       []*Ident // optional column list
	ColumnsRparen Pos      // position of column list right paren

	Values     Pos         // position of VALUES keyword
	ValueLists []*ExprList // lists of lists of values

	Select *SelectStatement // SELECT statement

	Default       Pos // position of DEFAULT keyword
	DefaultValues Pos // position of VALUES keyword after DEFAULT

	UpsertClause *UpsertClause // optional upsert clause
}

// Clone returns a deep copy of s.
func (s *InsertStatement) Clone() *InsertStatement {
	if s == nil {
		return nil
	}
	other := *s
	other.WithClause = s.WithClause.Clone()
	other.Table = s.Table.Clone()
	other.Alias = s.Alias.Clone()
	other.Columns = cloneIdents(s.Columns)
	other.ValueLists = cloneExprLists(s.ValueLists)
	other.Select = s.Select.Clone()
	other.UpsertClause = s.UpsertClause.Clone()
	return &other
}

// String returns the string representation of the statement.
func (s *InsertStatement) String() string {
	var buf bytes.Buffer
	if s.WithClause != nil {
		buf.WriteString(s.WithClause.String())
		buf.WriteString(" ")
	}

	if s.Replace.IsValid() {
		buf.WriteString("REPLACE")
	} else {
		buf.WriteString("INSERT")
		if s.InsertOrReplace.IsValid() {
			buf.WriteString(" OR REPLACE")
		} else if s.InsertOrRollback.IsValid() {
			buf.WriteString(" OR ROLLBACK")
		} else if s.InsertOrAbort.IsValid() {
			buf.WriteString(" OR ABORT")
		} else if s.InsertOrFail.IsValid() {
			buf.WriteString(" OR FAIL")
		} else if s.InsertOrIgnore.IsValid() {
			buf.WriteString(" OR IGNORE")
		}
	}

	fmt.Fprintf(&buf, " INTO %s", s.Table.String())
	if s.Alias != nil {
		fmt.Fprintf(&buf, " AS %s", s.Alias.String())
	}

	if len(s.Columns) != 0 {
		buf.WriteString(" (")
		for i, col := range s.Columns {
			if i != 0 {
				buf.WriteString(", ")
			}
			buf.WriteString(col.String())
		}
		buf.WriteString(")")
	}

	if s.DefaultValues.IsValid() {
		buf.WriteString(" DEFAULT VALUES")
	} else if s.Select != nil {
		fmt.Fprintf(&buf, " %s", s.Select.String())
	} else {
		buf.WriteString(" VALUES")
		for i := range s.ValueLists {
			if i != 0 {
				buf.WriteString(",")
			}
			buf.WriteString(" (")
			for j, expr := range s.ValueLists[i].Exprs {
				if j != 0 {
					buf.WriteString(", ")
				}
				buf.WriteString(expr.String())
			}
			buf.WriteString(")")
		}
	}

	if s.UpsertClause != nil {
		fmt.Fprintf(&buf, " %s", s.UpsertClause.String())
	}

	return buf.String()
}

type UpsertClause struct {
	On         Pos // position of ON keyword
	OnConflict Pos // position of CONFLICT keyword after ON

	Lparen    Pos              // position of column list left paren
	Columns   []*IndexedColumn // optional indexed column list
	Rparen    Pos              // position of column list right paren
	Where     Pos              // position of WHERE keyword
	WhereExpr Expr             // optional conditional expression

	Do              Pos           // position of DO keyword
	DoNothing       Pos           // position of NOTHING keyword after DO
	DoUpdate        Pos           // position of UPDATE keyword after DO
	DoUpdateSet     Pos           // position of SET keyword after DO UPDATE
	Assignments     []*Assignment // list of column assignments
	UpdateWhere     Pos           // position of WHERE keyword for DO UPDATE SET
	UpdateWhereExpr Expr          // optional conditional expression for DO UPDATE SET
}

// Clone returns a deep copy of c.
func (c *UpsertClause) Clone() *UpsertClause {
	if c == nil {
		return nil
	}
	other := *c
	other.Columns = cloneIndexedColumns(c.Columns)
	other.WhereExpr = CloneExpr(c.WhereExpr)
	other.Assignments = cloneAssignments(c.Assignments)
	other.UpdateWhereExpr = CloneExpr(c.UpdateWhereExpr)
	return &other
}

// String returns the string representation of the clause.
func (c *UpsertClause) String() string {
	var buf bytes.Buffer
	buf.WriteString("ON CONFLICT")

	if len(c.Columns) != 0 {
		buf.WriteString(" (")
		for i, col := range c.Columns {
			if i != 0 {
				buf.WriteString(", ")
			}
			buf.WriteString(col.String())
		}
		buf.WriteString(")")

		if c.WhereExpr != nil {
			fmt.Fprintf(&buf, " WHERE %s", c.WhereExpr.String())
		}
	}

	buf.WriteString(" DO")
	if c.DoNothing.IsValid() {
		buf.WriteString(" NOTHING")
	} else {
		buf.WriteString(" UPDATE SET ")
		for i := range c.Assignments {
			if i != 0 {
				buf.WriteString(", ")
			}
			buf.WriteString(c.Assignments[i].String())
		}

		if c.UpdateWhereExpr != nil {
			fmt.Fprintf(&buf, " WHERE %s", c.UpdateWhereExpr.String())
		}
	}

	return buf.String()
}

type UpdateStatement struct {
	WithClause *WithClause // clause containing CTEs

	Update           Pos // position of UPDATE keyword
	UpdateOr         Pos // position of OR keyword after UPDATE
	UpdateOrReplace  Pos // position of REPLACE keyword after UPDATE OR
	UpdateOrRollback Pos // position of ROLLBACK keyword after UPDATE OR
	UpdateOrAbort    Pos // position of ABORT keyword after UPDATE OR
	UpdateOrFail     Pos // position of FAIL keyword after UPDATE OR
	UpdateOrIgnore   Pos // position of IGNORE keyword after UPDATE OR

	Table *QualifiedTableName // table name

	Set         Pos           // position of SET keyword
	Assignments []*Assignment // list of column assignments
	Where       Pos           // position of WHERE keyword
	WhereExpr   Expr          // conditional expression
}

// Clone returns a deep copy of s.
func (s *UpdateStatement) Clone() *UpdateStatement {
	if s == nil {
		return nil
	}
	other := *s
	other.WithClause = s.WithClause.Clone()
	other.Table = s.Table.Clone()
	other.Assignments = cloneAssignments(s.Assignments)
	other.WhereExpr = CloneExpr(s.WhereExpr)
	return &other
}

// String returns the string representation of the clause.
func (s *UpdateStatement) String() string {
	var buf bytes.Buffer
	if s.WithClause != nil {
		buf.WriteString(s.WithClause.String())
		buf.WriteString(" ")
	}

	buf.WriteString("UPDATE")
	if s.UpdateOrRollback.IsValid() {
		buf.WriteString(" OR ROLLBACK")
	} else if s.UpdateOrAbort.IsValid() {
		buf.WriteString(" OR ABORT")
	} else if s.UpdateOrReplace.IsValid() {
		buf.WriteString(" OR REPLACE")
	} else if s.UpdateOrFail.IsValid() {
		buf.WriteString(" OR FAIL")
	} else if s.UpdateOrIgnore.IsValid() {
		buf.WriteString(" OR IGNORE")
	}

	fmt.Fprintf(&buf, " %s ", s.Table.String())

	buf.WriteString("SET ")
	for i := range s.Assignments {
		if i != 0 {
			buf.WriteString(", ")
		}
		buf.WriteString(s.Assignments[i].String())
	}

	if s.WhereExpr != nil {
		fmt.Fprintf(&buf, " WHERE %s", s.WhereExpr.String())
	}

	return buf.String()
}

type DeleteStatement struct {
	WithClause *WithClause         // clause containing CTEs
	Delete     Pos                 // position of UPDATE keyword
	From       Pos                 // position of FROM keyword
	Table      *QualifiedTableName // table name

	Where     Pos  // position of WHERE keyword
	WhereExpr Expr // conditional expression

	Order         Pos             // position of ORDER keyword
	OrderBy       Pos             // position of BY keyword after ORDER
	OrderingTerms []*OrderingTerm // terms of ORDER BY clause

	Limit       Pos  // position of LIMIT keyword
	LimitExpr   Expr // limit expression
	Offset      Pos  // position of OFFSET keyword
	OffsetComma Pos  // position of COMMA (instead of OFFSET)
	OffsetExpr  Expr // offset expression
}

// Clone returns a deep copy of s.
func (s *DeleteStatement) Clone() *DeleteStatement {
	if s == nil {
		return nil
	}
	other := *s
	other.WithClause = s.WithClause.Clone()
	other.Table = s.Table.Clone()
	other.WhereExpr = CloneExpr(s.WhereExpr)
	other.OrderingTerms = cloneOrderingTerms(s.OrderingTerms)
	other.LimitExpr = CloneExpr(s.LimitExpr)
	other.OffsetExpr = CloneExpr(s.OffsetExpr)
	return &other
}

// String returns the string representation of the clause.
func (s *DeleteStatement) String() string {
	var buf bytes.Buffer
	if s.WithClause != nil {
		buf.WriteString(s.WithClause.String())
		buf.WriteString(" ")
	}

	fmt.Fprintf(&buf, "DELETE FROM %s", s.Table.String())
	if s.WhereExpr != nil {
		fmt.Fprintf(&buf, " WHERE %s", s.WhereExpr.String())
	}

	// Write ORDER BY.
	if len(s.OrderingTerms) != 0 {
		buf.WriteString(" ORDER BY ")
		for i, term := range s.OrderingTerms {
			if i != 0 {
				buf.WriteString(", ")
			}
			buf.WriteString(term.String())
		}
	}

	// Write LIMIT/OFFSET.
	if s.LimitExpr != nil {
		fmt.Fprintf(&buf, " LIMIT %s", s.LimitExpr.String())
		if s.OffsetExpr != nil {
			fmt.Fprintf(&buf, " OFFSET %s", s.OffsetExpr.String())
		}
	}

	return buf.String()
}

// Assignment is used within the UPDATE statement & upsert clause.
// It is similiar to an expression except that it must be an equality.
type Assignment struct {
	Lparen  Pos      // position of column list left paren
	Columns []*Ident // column list
	Rparen  Pos      // position of column list right paren
	Eq      Pos      // position of =
	Expr    Expr     // assigned expression
}

// Clone returns a deep copy of a.
func (a *Assignment) Clone() *Assignment {
	if a == nil {
		return nil
	}
	other := *a
	other.Columns = cloneIdents(a.Columns)
	other.Expr = CloneExpr(a.Expr)
	return &other
}

func cloneAssignments(a []*Assignment) []*Assignment {
	if a == nil {
		return nil
	}
	other := make([]*Assignment, len(a))
	for i := range a {
		other[i] = a[i].Clone()
	}
	return other
}

// String returns the string representation of the clause.
func (a *Assignment) String() string {
	var buf bytes.Buffer
	if len(a.Columns) == 1 {
		buf.WriteString(a.Columns[0].String())
	} else if len(a.Columns) > 1 {
		buf.WriteString("(")
		for i, col := range a.Columns {
			if i != 0 {
				buf.WriteString(", ")
			}
			buf.WriteString(col.String())
		}
		buf.WriteString(")")
	}

	fmt.Fprintf(&buf, " = %s", a.Expr.String())
	return buf.String()
}

type IndexedColumn struct {
	X    Expr // column expression
	Asc  Pos  // position of optional ASC keyword
	Desc Pos  // position of optional DESC keyword
}

// Clone returns a deep copy of c.
func (c *IndexedColumn) Clone() *IndexedColumn {
	if c == nil {
		return nil
	}
	other := *c
	other.X = CloneExpr(c.X)
	return &other
}

func cloneIndexedColumns(a []*IndexedColumn) []*IndexedColumn {
	if a == nil {
		return nil
	}
	other := make([]*IndexedColumn, len(a))
	for i := range a {
		other[i] = a[i].Clone()
	}
	return other
}

// String returns the string representation of the column.
func (c *IndexedColumn) String() string {
	if c.Asc.IsValid() {
		return fmt.Sprintf("%s ASC", c.X.String())
	} else if c.Desc.IsValid() {
		return fmt.Sprintf("%s DESC", c.X.String())
	}
	return c.X.String()
}

type SelectStatement struct {
	WithClause *WithClause // clause containing CTEs

	Values     Pos         // position of VALUES keyword
	ValueLists []*ExprList // lists of lists of values

	Select   Pos             // position of SELECT keyword
	Distinct Pos             // position of DISTINCT keyword
	All      Pos             // position of ALL keyword
	Columns  []*ResultColumn // list of result columns in the SELECT clause

	From   Pos    // position of FROM keyword
	Source Source // chain of tables & subqueries in FROM clause

	Where     Pos  // position of WHERE keyword
	WhereExpr Expr // condition for WHERE clause

	Group        Pos    // position of GROUP keyword
	GroupBy      Pos    // position of BY keyword after GROUP
	GroupByExprs []Expr // group by expression list
	Having       Pos    // position of HAVING keyword
	HavingExpr   Expr   // HAVING expression

	Window  Pos       // position of WINDOW keyword
	Windows []*Window // window list

	Union     Pos              // position of UNION keyword
	UnionAll  Pos              // position of ALL keyword after UNION
	Intersect Pos              // position of INTERSECT keyword
	Except    Pos              // position of EXCEPT keyword
	Compound  *SelectStatement // compounded SELECT statement

	Order         Pos             // position of ORDER keyword
	OrderBy       Pos             // position of BY keyword after ORDER
	OrderingTerms []*OrderingTerm // terms of ORDER BY clause

	Limit       Pos  // position of LIMIT keyword
	LimitExpr   Expr // limit expression
	Offset      Pos  // position of OFFSET keyword
	OffsetComma Pos  // position of COMMA (instead of OFFSET)
	OffsetExpr  Expr // offset expression
}

// Clone returns a deep copy of s.
func (s *SelectStatement) Clone() *SelectStatement {
	if s == nil {
		return nil
	}
	other := *s
	other.WithClause = s.WithClause.Clone()
	other.ValueLists = cloneExprLists(s.ValueLists)
	other.Columns = cloneResultColumns(s.Columns)
	other.Source = CloneSource(s.Source)
	other.WhereExpr = CloneExpr(s.WhereExpr)
	other.GroupByExprs = cloneExprs(s.GroupByExprs)
	other.HavingExpr = CloneExpr(s.HavingExpr)
	other.Windows = cloneWindows(s.Windows)
	other.Compound = s.Compound.Clone()
	other.OrderingTerms = cloneOrderingTerms(s.OrderingTerms)
	other.LimitExpr = CloneExpr(s.LimitExpr)
	other.OffsetExpr = CloneExpr(s.OffsetExpr)
	return &other
}

// IsAggregate returns true if statement contains aggregate columns.
func (s *SelectStatement) IsAggregate() bool {
	for _, col := range s.Columns {
		if col.IsAggregate() {
			return true
		}
	}
	return false
}

// HasWildcard returns true any result column contains a wildcard (STAR).
func (s *SelectStatement) HasWildcard() bool {
	for _, col := range s.Columns {
		// Unqualified wildcard.
		if col.Star.IsValid() {
			return true
		}

		// Table-qualified wildcard.
		if ref, ok := col.Expr.(*QualifiedRef); ok && ref.Star.IsValid() {
			return true
		}
	}

	return false
}

// String returns the string representation of the statement.
func (s *SelectStatement) String() string {
	var buf bytes.Buffer
	if s.WithClause != nil {
		buf.WriteString(s.WithClause.String())
		buf.WriteString(" ")
	}

	if len(s.ValueLists) > 0 {
		buf.WriteString("VALUES ")
		for i, exprs := range s.ValueLists {
			if i != 0 {
				buf.WriteString(", ")
			}

			buf.WriteString("(")
			for j, expr := range exprs.Exprs {
				if j != 0 {
					buf.WriteString(", ")
				}
				buf.WriteString(expr.String())
			}
			buf.WriteString(")")
		}
	} else {
		buf.WriteString("SELECT ")
		if s.Distinct.IsValid() {
			buf.WriteString("DISTINCT ")
		} else if s.All.IsValid() {
			buf.WriteString("ALL ")
		}

		for i, col := range s.Columns {
			if i != 0 {
				buf.WriteString(", ")
			}
			buf.WriteString(col.String())
		}

		if s.Source != nil {
			fmt.Fprintf(&buf, " FROM %s", s.Source.String())
		}

		if s.WhereExpr != nil {
			fmt.Fprintf(&buf, " WHERE %s", s.WhereExpr.String())
		}

		if len(s.GroupByExprs) != 0 {
			buf.WriteString(" GROUP BY ")
			for i, expr := range s.GroupByExprs {
				if i != 0 {
					buf.WriteString(", ")
				}
				buf.WriteString(expr.String())
			}

			if s.HavingExpr != nil {
				fmt.Fprintf(&buf, " HAVING %s", s.HavingExpr.String())
			}
		}

		if len(s.Windows) != 0 {
			buf.WriteString(" WINDOW ")
			for i, window := range s.Windows {
				if i != 0 {
					buf.WriteString(", ")
				}
				buf.WriteString(window.String())
			}
		}
	}

	// Write compound operator.
	if s.Compound != nil {
		switch {
		case s.Union.IsValid():
			buf.WriteString(" UNION")
			if s.UnionAll.IsValid() {
				buf.WriteString(" ALL")
			}
		case s.Intersect.IsValid():
			buf.WriteString(" INTERSECT")
		case s.Except.IsValid():
			buf.WriteString(" EXCEPT")
		}

		fmt.Fprintf(&buf, " %s", s.Compound.String())
	}

	// Write ORDER BY.
	if len(s.OrderingTerms) != 0 {
		buf.WriteString(" ORDER BY ")
		for i, term := range s.OrderingTerms {
			if i != 0 {
				buf.WriteString(", ")
			}
			buf.WriteString(term.String())
		}
	}

	// Write LIMIT/OFFSET.
	if s.LimitExpr != nil {
		fmt.Fprintf(&buf, " LIMIT %s", s.LimitExpr.String())
		if s.OffsetExpr != nil {
			fmt.Fprintf(&buf, " OFFSET %s", s.OffsetExpr.String())
		}
	}

	return buf.String()
}

type ResultColumn struct {
	Star  Pos    // position of *
	Expr  Expr   // column expression (may be "tbl.*")
	As    Pos    // position of AS keyword
	Alias *Ident // alias name
}

// Name returns the column name. Uses the alias, if specified.
// Otherwise returns a generated name.
func (c *ResultColumn) Name() string {
	if c.Alias != nil {
		return IdentName(c.Alias)
	}

	switch expr := c.Expr.(type) {
	case *Call:
		return strings.ToLower(IdentName(expr.Name))
	case *Ident:
		return IdentName(expr)
	case *QualifiedRef:
		return IdentName(expr.Column)
	default:
		return ""
	}
}

// IsAggregate returns true if column contains an aggregate function expression.
func (c *ResultColumn) IsAggregate() bool {
	if c.Star.IsValid() {
		return false
	}
	return c.Expr.IsAggregate()
}

// Clone returns a deep copy of c.
func (c *ResultColumn) Clone() *ResultColumn {
	if c == nil {
		return nil
	}
	other := *c
	other.Expr = CloneExpr(c.Expr)
	other.Alias = c.Alias.Clone()
	return &other
}

func cloneResultColumns(a []*ResultColumn) []*ResultColumn {
	if a == nil {
		return nil
	}
	other := make([]*ResultColumn, len(a))
	for i := range a {
		other[i] = a[i].Clone()
	}
	return other
}

// String returns the string representation of the column.
func (c *ResultColumn) String() string {
	if c.Star.IsValid() {
		return "*"
	} else if c.Alias != nil {
		return fmt.Sprintf("%s AS %s", c.Expr.String(), c.Alias.String())
	}
	return c.Expr.String()
}

type QualifiedTableName struct {
	Name       *Ident // table name
	As         Pos    // position of AS keyword
	Alias      *Ident // optional table alias
	Indexed    Pos    // position of INDEXED keyword
	IndexedBy  Pos    // position of BY keyword after INDEXED
	Not        Pos    // position of NOT keyword before INDEXED
	NotIndexed Pos    // position of NOT keyword before INDEXED
	Index      *Ident // name of index
}

// TableName returns the name used to identify n.
// Returns the alias, if one is specified. Otherwise returns the name.
func (n *QualifiedTableName) TableName() string {
	if s := IdentName(n.Alias); s != "" {
		return s
	}
	return IdentName(n.Name)
}

// Clone returns a deep copy of n.
func (n *QualifiedTableName) Clone() *QualifiedTableName {
	if n == nil {
		return nil
	}
	other := *n
	other.Name = n.Name.Clone()
	other.Alias = n.Alias.Clone()
	other.Index = n.Index.Clone()
	return &other
}

// String returns the string representation of the table name.
func (n *QualifiedTableName) String() string {
	var buf bytes.Buffer
	buf.WriteString(n.Name.String())
	if n.Alias != nil {
		fmt.Fprintf(&buf, " AS %s", n.Alias.String())
	}

	if n.Index != nil {
		fmt.Fprintf(&buf, " INDEXED BY %s", n.Index.String())
	} else if n.NotIndexed.IsValid() {
		buf.WriteString(" NOT INDEXED")
	}
	return buf.String()
}

type ParenSource struct {
	Lparen Pos    // position of left paren
	X      Source // nested source
	Rparen Pos    // position of right paren
	As     Pos    // position of AS keyword (select source only)
	Alias  *Ident // optional table alias (select source only)
}

// Clone returns a deep copy of s.
func (s *ParenSource) Clone() *ParenSource {
	if s == nil {
		return nil
	}
	other := *s
	other.X = CloneSource(s.X)
	other.Alias = s.Alias.Clone()
	return &other
}

// String returns the string representation of the source.
func (s *ParenSource) String() string {
	if s.Alias != nil {
		return fmt.Sprintf("(%s) AS %s", s.X.String(), s.Alias.String())
	}
	return fmt.Sprintf("(%s)", s.X.String())
}

type JoinClause struct {
	X          Source         // lhs source
	Operator   *JoinOperator  // join operator
	Y          Source         // rhs source
	Constraint JoinConstraint // join constraint
}

// Clone returns a deep copy of c.
func (c *JoinClause) Clone() *JoinClause {
	if c == nil {
		return nil
	}
	other := *c
	other.X = CloneSource(c.X)
	other.Y = CloneSource(c.Y)
	other.Constraint = CloneJoinConstraint(c.Constraint)
	return &other
}

// String returns the string representation of the clause.
func (c *JoinClause) String() string {
	var buf bytes.Buffer
	fmt.Fprintf(&buf, "%s%s%s", c.X.String(), c.Operator.String(), c.Y.String())
	if c.Constraint != nil {
		fmt.Fprintf(&buf, " %s", c.Constraint.String())
	}
	return buf.String()
}

type JoinOperator struct {
	Comma   Pos // position of comma
	Natural Pos // position of NATURAL keyword
	Left    Pos // position of LEFT keyword
	Outer   Pos // position of OUTER keyword
	Inner   Pos // position of INNER keyword
	Cross   Pos // position of CROSS keyword
	Join    Pos // position of JOIN keyword
}

// Clone returns a deep copy of op.
func (op *JoinOperator) Clone() *JoinOperator {
	if op == nil {
		return nil
	}
	other := *op
	return &other
}

// String returns the string representation of the operator.
func (op *JoinOperator) String() string {
	if op.Comma.IsValid() {
		return ", "
	}

	var buf bytes.Buffer
	if op.Natural.IsValid() {
		buf.WriteString(" NATURAL")
	}
	if op.Left.IsValid() {
		buf.WriteString(" LEFT")
		if op.Outer.IsValid() {
			buf.WriteString(" OUTER")
		}
	} else if op.Inner.IsValid() {
		buf.WriteString(" INNER")
	} else if op.Cross.IsValid() {
		buf.WriteString(" CROSS")
	}
	buf.WriteString(" JOIN ")

	return buf.String()
}

type OnConstraint struct {
	On Pos  // position of ON keyword
	X  Expr // constraint expression
}

// Clone returns a deep copy of c.
func (c *OnConstraint) Clone() *OnConstraint {
	if c == nil {
		return nil
	}
	other := *c
	other.X = CloneExpr(c.X)
	return &other
}

// String returns the string representation of the constraint.
func (c *OnConstraint) String() string {
	return "ON " + c.X.String()
}

type UsingConstraint struct {
	Using   Pos      // position of USING keyword
	Lparen  Pos      // position of left paren
	Columns []*Ident // column list
	Rparen  Pos      // position of right paren
}

// Clone returns a deep copy of c.
func (c *UsingConstraint) Clone() *UsingConstraint {
	if c == nil {
		return nil
	}
	other := *c
	other.Columns = cloneIdents(c.Columns)
	return &other
}

// String returns the string representation of the constraint.
func (c *UsingConstraint) String() string {
	var buf bytes.Buffer
	buf.WriteString("USING (")
	for i, col := range c.Columns {
		if i != 0 {
			buf.WriteString(", ")
		}
		buf.WriteString(col.String())
	}
	buf.WriteString(")")
	return buf.String()
}

type WithClause struct {
	With      Pos    // position of WITH keyword
	Recursive Pos    // position of RECURSIVE keyword
	CTEs      []*CTE // common table expressions
}

// Clone returns a deep copy of c.
func (c *WithClause) Clone() *WithClause {
	if c == nil {
		return nil
	}
	other := *c
	other.CTEs = cloneCTEs(c.CTEs)
	return &other
}

// String returns the string representation of the clause.
func (c *WithClause) String() string {
	var buf bytes.Buffer
	buf.WriteString("WITH ")
	if c.Recursive.IsValid() {
		buf.WriteString("RECURSIVE ")
	}

	for i, cte := range c.CTEs {
		if i != 0 {
			buf.WriteString(", ")
		}
		buf.WriteString(cte.String())
	}

	return buf.String()
}

// CTE represents an AST node for a common table expression.
type CTE struct {
	TableName     *Ident           // table name
	ColumnsLparen Pos              // position of column list left paren
	Columns       []*Ident         // optional column list
	ColumnsRparen Pos              // position of column list right paren
	As            Pos              // position of AS keyword
	SelectLparen  Pos              // position of select left paren
	Select        *SelectStatement // select statement
	SelectRparen  Pos              // position of select right paren
}

// Clone returns a deep copy of cte.
func (cte *CTE) Clone() *CTE {
	if cte == nil {
		return nil
	}
	other := *cte
	other.TableName = cte.TableName.Clone()
	other.Columns = cloneIdents(cte.Columns)
	other.Select = cte.Select.Clone()
	return &other
}

func cloneCTEs(a []*CTE) []*CTE {
	if a == nil {
		return nil
	}
	other := make([]*CTE, len(a))
	for i := range a {
		other[i] = a[i].Clone()
	}
	return other
}

// String returns the string representation of the CTE.
func (cte *CTE) String() string {
	var buf bytes.Buffer
	fmt.Fprintf(&buf, "%s", cte.TableName.String())

	if len(cte.Columns) != 0 {
		buf.WriteString(" (")
		for i, col := range cte.Columns {
			if i != 0 {
				buf.WriteString(", ")
			}
			buf.WriteString(col.String())
		}
		buf.WriteString(")")
	}

	fmt.Fprintf(&buf, " AS (%s)", cte.Select.String())

	return buf.String()
}

type ParenExpr struct {
	Lparen Pos  // position of left paren
	X      Expr // parenthesized expression
	Rparen Pos  // position of right paren
}

// IsAggregate returns true if inner expression has an aggregate function.
func (expr *ParenExpr) IsAggregate() bool { return false }

// Clone returns a deep copy of expr.
func (expr *ParenExpr) Clone() *ParenExpr {
	if expr == nil {
		return nil
	}
	other := *expr
	other.X = CloneExpr(expr.X)
	return &other
}

// String returns the string representation of the expression.
func (expr *ParenExpr) String() string {
	return fmt.Sprintf("(%s)", expr.X.String())
}

type Window struct {
	Name       *Ident            // name of window
	As         Pos               // position of AS keyword
	Definition *WindowDefinition // window definition
}

// Clone returns a deep copy of w.
func (w *Window) Clone() *Window {
	if w == nil {
		return nil
	}
	other := *w
	other.Name = w.Name.Clone()
	other.Definition = w.Definition.Clone()
	return &other
}

func cloneWindows(a []*Window) []*Window {
	if a == nil {
		return nil
	}
	other := make([]*Window, len(a))
	for i := range a {
		other[i] = a[i].Clone()
	}
	return other
}

// String returns the string representation of the window.
func (w *Window) String() string {
	return fmt.Sprintf("%s AS %s", w.Name.String(), w.Definition.String())
}

type WindowDefinition struct {
	Lparen        Pos             // position of left paren
	Base          *Ident          // base window name
	Partition     Pos             // position of PARTITION keyword
	PartitionBy   Pos             // position of BY keyword (after PARTITION)
	Partitions    []Expr          // partition expressions
	Order         Pos             // position of ORDER keyword
	OrderBy       Pos             // position of BY keyword (after ORDER)
	OrderingTerms []*OrderingTerm // ordering terms
	Frame         *FrameSpec      // frame
	Rparen        Pos             // position of right paren
}

// Clone returns a deep copy of d.
func (d *WindowDefinition) Clone() *WindowDefinition {
	if d == nil {
		return nil
	}
	other := *d
	other.Base = d.Base.Clone()
	other.Partitions = cloneExprs(d.Partitions)
	other.OrderingTerms = cloneOrderingTerms(d.OrderingTerms)
	other.Frame = d.Frame.Clone()
	return &other
}

// String returns the string representation of the window definition.
func (d *WindowDefinition) String() string {
	var buf bytes.Buffer
	buf.WriteString("(")
	if d.Base != nil {
		buf.WriteString(d.Base.String())
	}

	if len(d.Partitions) != 0 {
		if buf.Len() > 1 {
			buf.WriteString(" ")
		}
		buf.WriteString("PARTITION BY ")

		for i, p := range d.Partitions {
			if i != 0 {
				buf.WriteString(", ")
			}
			buf.WriteString(p.String())
		}
	}

	if len(d.OrderingTerms) != 0 {
		if buf.Len() > 1 {
			buf.WriteString(" ")
		}
		buf.WriteString("ORDER BY ")

		for i, term := range d.OrderingTerms {
			if i != 0 {
				buf.WriteString(", ")
			}
			buf.WriteString(term.String())
		}
	}

	if d.Frame != nil {
		if buf.Len() > 1 {
			buf.WriteString(" ")
		}
		buf.WriteString(d.Frame.String())
	}

	buf.WriteString(")")

	return buf.String()
}
