mirror of
https://github.com/featurebasedb/featurebase.git
synced 2026-08-28 10:54:59 +00:00
```bash for file in `cat diffys`; do printf '%s\n%s\n' "// Copyright 2021 Molecula Corp. All rights reserved." "$(cat $file)" >$file; done ```
3716 lines
92 KiB
Go
3716 lines
92 KiB
Go
// 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()
|
|
}
|