mirror of
https://github.com/featurebasedb/featurebase.git
synced 2026-08-28 10:54:59 +00:00
We forward-ported a handful of tests from the previous parser which relied on LIMIT clauses, but then we didn't support that. Now that we do, we uncomment most of these tests, and actually give them the correct data structures to compare with. We leave two tests commented out. One was using `limit 10, 5` to express a limit plus offset, and the other is using `not fld = 1` as a WHERE clause, but we don't support unary-not to negate other expressions. In the process, we discover that converting a SELECT with a LIMIT clause back to a string has a missing space, and fix that.
4857 lines
119 KiB
Go
4857 lines
119 KiB
Go
// Copyright 2021 Molecula Corp. All rights reserved.
|
|
package parser
|
|
|
|
import (
|
|
"bytes"
|
|
"fmt"
|
|
"strings"
|
|
"time"
|
|
)
|
|
|
|
type Node interface {
|
|
node()
|
|
fmt.Stringer
|
|
}
|
|
|
|
func (*AlterDatabaseStatement) node() {}
|
|
func (*AlterTableStatement) node() {}
|
|
func (*AlterViewStatement) node() {}
|
|
func (*AnalyzeStatement) node() {}
|
|
func (*Assignment) node() {}
|
|
func (*ShowDatabasesStatement) node() {}
|
|
func (*ShowTablesStatement) node() {}
|
|
func (*ShowColumnsStatement) node() {}
|
|
func (*ShowCreateTableStatement) node() {}
|
|
func (*BeginStatement) node() {}
|
|
func (*BinaryExpr) node() {}
|
|
func (*BoolLit) node() {}
|
|
func (*BulkInsertMapDefinition) node() {}
|
|
func (*BulkInsertStatement) node() {}
|
|
func (*CacheTypeConstraint) node() {}
|
|
func (*Call) node() {}
|
|
func (*CaseBlock) node() {}
|
|
func (*CaseExpr) node() {}
|
|
func (*CastExpr) node() {}
|
|
func (*CheckConstraint) node() {}
|
|
func (*ColumnDefinition) node() {}
|
|
func (*CopyStatement) node() {}
|
|
func (*CommitStatement) node() {}
|
|
func (*CreateDatabaseStatement) node() {}
|
|
func (*CreateIndexStatement) node() {}
|
|
func (*CreateTableStatement) node() {}
|
|
func (*CreateFunctionStatement) node() {}
|
|
func (*CreateModelStatement) node() {}
|
|
func (*CreateViewStatement) node() {}
|
|
func (*DateLit) node() {}
|
|
func (*DefaultConstraint) node() {}
|
|
func (*DeleteStatement) node() {}
|
|
func (*DropDatabaseStatement) node() {}
|
|
func (*DropIndexStatement) node() {}
|
|
func (*DropTableStatement) node() {}
|
|
func (*DropFunctionStatement) node() {}
|
|
func (*DropViewStatement) node() {}
|
|
func (*DropModelStatement) node() {}
|
|
func (*Exists) node() {}
|
|
func (*ExplainStatement) node() {}
|
|
func (*ExprList) node() {}
|
|
func (*FilterClause) node() {}
|
|
func (*FloatLit) node() {}
|
|
func (*ForeignKeyArg) node() {}
|
|
func (*ForeignKeyConstraint) node() {}
|
|
func (*FrameSpec) node() {}
|
|
func (*Ident) node() {}
|
|
func (*Variable) node() {}
|
|
func (*SysVariable) node() {}
|
|
func (*IndexedColumn) node() {}
|
|
func (*InsertStatement) node() {}
|
|
func (*JoinClause) node() {}
|
|
func (*JoinOperator) node() {}
|
|
func (*KeyPartitionsOption) node() {}
|
|
func (*MinConstraint) node() {}
|
|
func (*MaxConstraint) node() {}
|
|
func (*NotNullConstraint) node() {}
|
|
func (*NullLit) node() {}
|
|
func (*IntegerLit) node() {}
|
|
func (*OnConstraint) node() {}
|
|
func (*OrderingTerm) node() {}
|
|
func (*OverClause) node() {}
|
|
func (*ParenExpr) node() {}
|
|
func (*PredictStatement) node() {}
|
|
func (*SetLiteralExpr) node() {}
|
|
func (*ParenSource) node() {}
|
|
func (*PrimaryKeyConstraint) node() {}
|
|
func (*QualifiedRef) node() {}
|
|
func (*QualifiedTableName) node() {}
|
|
func (*Range) node() {}
|
|
func (*ReturnStatement) node() {}
|
|
func (*ReleaseStatement) node() {}
|
|
func (*ResultColumn) node() {}
|
|
func (*RollbackStatement) node() {}
|
|
func (*SavepointStatement) node() {}
|
|
func (*SelectStatement) node() {}
|
|
func (*StringLit) node() {}
|
|
func (*TableValuedFunction) node() {}
|
|
func (*TimeUnitConstraint) node() {}
|
|
func (*TimeQuantumConstraint) node() {}
|
|
func (*TupleLiteralExpr) node() {}
|
|
func (*Type) node() {}
|
|
func (*UnaryExpr) node() {}
|
|
func (*UniqueConstraint) node() {}
|
|
func (*UnitsOption) node() {}
|
|
func (*UpdateStatement) node() {}
|
|
func (*UpsertClause) node() {}
|
|
func (*UsingConstraint) node() {}
|
|
func (*Window) node() {}
|
|
func (*WindowDefinition) node() {}
|
|
func (*WithClause) node() {}
|
|
func (*CommentOption) node() {}
|
|
|
|
type Statement interface {
|
|
Node
|
|
stmt()
|
|
}
|
|
|
|
func (*AlterDatabaseStatement) stmt() {}
|
|
func (*AlterTableStatement) stmt() {}
|
|
func (*AlterViewStatement) stmt() {}
|
|
func (*AnalyzeStatement) stmt() {}
|
|
func (*BeginStatement) stmt() {}
|
|
func (*CopyStatement) stmt() {}
|
|
func (*BulkInsertStatement) stmt() {}
|
|
func (*ShowDatabasesStatement) stmt() {}
|
|
func (*ShowTablesStatement) stmt() {}
|
|
func (*ShowColumnsStatement) stmt() {}
|
|
func (*ShowCreateTableStatement) stmt() {}
|
|
func (*CommitStatement) stmt() {}
|
|
func (*CreateDatabaseStatement) stmt() {}
|
|
func (*CreateIndexStatement) stmt() {}
|
|
func (*CreateTableStatement) stmt() {}
|
|
func (*CreateFunctionStatement) stmt() {}
|
|
func (*CreateModelStatement) stmt() {}
|
|
func (*CreateViewStatement) stmt() {}
|
|
func (*DeleteStatement) stmt() {}
|
|
func (*DropDatabaseStatement) stmt() {}
|
|
func (*DropIndexStatement) stmt() {}
|
|
func (*DropTableStatement) stmt() {}
|
|
func (*DropFunctionStatement) stmt() {}
|
|
func (*DropViewStatement) stmt() {}
|
|
func (*DropModelStatement) stmt() {}
|
|
func (*PredictStatement) stmt() {}
|
|
func (*ExplainStatement) stmt() {}
|
|
func (*InsertStatement) stmt() {}
|
|
func (*ReleaseStatement) stmt() {}
|
|
func (*ReturnStatement) 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 *AlterDatabaseStatement:
|
|
return stmt.Clone()
|
|
case *AlterTableStatement:
|
|
return stmt.Clone()
|
|
case *AlterViewStatement:
|
|
return stmt.Clone()
|
|
case *AnalyzeStatement:
|
|
return stmt.Clone()
|
|
case *BeginStatement:
|
|
return stmt.Clone()
|
|
case *CommitStatement:
|
|
return stmt.Clone()
|
|
case *CreateDatabaseStatement:
|
|
return stmt.Clone()
|
|
case *CreateIndexStatement:
|
|
return stmt.Clone()
|
|
case *CreateTableStatement:
|
|
return stmt.Clone()
|
|
case *CreateFunctionStatement:
|
|
return stmt.Clone()
|
|
case *CreateViewStatement:
|
|
return stmt.Clone()
|
|
case *DeleteStatement:
|
|
return stmt.Clone()
|
|
case *DropDatabaseStatement:
|
|
return stmt.Clone()
|
|
case *DropIndexStatement:
|
|
return stmt.Clone()
|
|
case *DropTableStatement:
|
|
return stmt.Clone()
|
|
case *DropFunctionStatement:
|
|
return stmt.Clone()
|
|
case *DropViewStatement:
|
|
return stmt.Clone()
|
|
case *DropModelStatement:
|
|
return stmt.Clone()
|
|
case *ExplainStatement:
|
|
return stmt.Clone()
|
|
case *InsertStatement:
|
|
return stmt.Clone()
|
|
case *BulkInsertStatement:
|
|
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()
|
|
case *ShowTablesStatement:
|
|
return stmt.Clone()
|
|
case *ShowColumnsStatement:
|
|
return stmt.Clone()
|
|
case *ShowCreateTableStatement:
|
|
return stmt.Clone()
|
|
case *ShowDatabasesStatement:
|
|
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.Source
|
|
default:
|
|
return nil
|
|
}
|
|
}
|
|
|
|
type Expr interface {
|
|
Node
|
|
expr()
|
|
|
|
IsLiteral() bool
|
|
DataType() ExprDataType
|
|
Pos() Pos
|
|
}
|
|
|
|
func (*BinaryExpr) expr() {}
|
|
func (*BoolLit) expr() {}
|
|
func (*Call) expr() {}
|
|
func (*CaseExpr) expr() {}
|
|
func (*CaseBlock) expr() {}
|
|
func (*CastExpr) expr() {}
|
|
func (*DateLit) expr() {}
|
|
func (*Exists) expr() {}
|
|
func (*ExprList) expr() {}
|
|
func (*Ident) expr() {}
|
|
func (*Variable) expr() {}
|
|
func (*SysVariable) expr() {}
|
|
func (*NullLit) expr() {}
|
|
func (*IntegerLit) expr() {}
|
|
func (*FloatLit) expr() {}
|
|
func (*ParenExpr) expr() {}
|
|
func (*SetLiteralExpr) expr() {}
|
|
func (*TupleLiteralExpr) expr() {}
|
|
func (*QualifiedRef) expr() {}
|
|
func (*Range) expr() {}
|
|
func (*StringLit) expr() {}
|
|
func (*UnaryExpr) expr() {}
|
|
func (*SelectStatement) 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 *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 *FloatLit:
|
|
return expr.Clone()
|
|
case *IntegerLit:
|
|
return expr.Clone()
|
|
case *ParenExpr:
|
|
return expr.Clone()
|
|
case *QualifiedRef:
|
|
return expr.Clone()
|
|
case *Range:
|
|
return expr.Clone()
|
|
case *StringLit:
|
|
return expr.Clone()
|
|
case *TupleLiteralExpr:
|
|
return expr.Clone()
|
|
case *UnaryExpr:
|
|
return expr.Clone()
|
|
case *Variable:
|
|
return expr.Clone()
|
|
case *SysVariable:
|
|
return expr.Clone()
|
|
case *DateLit:
|
|
return expr.Clone()
|
|
case *SetLiteralExpr:
|
|
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
|
|
}
|
|
|
|
// 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()
|
|
}
|
|
|
|
// 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)
|
|
}
|
|
}
|
|
|
|
// SourceOutputColumn is an identifier that is either a possible output column
|
|
// for a Source or a referenced output column for a Source. These are computed during
|
|
// the analysis phase
|
|
type SourceOutputColumn struct {
|
|
TableName string
|
|
ColumnName string
|
|
ColumnIndex int
|
|
Datatype ExprDataType
|
|
}
|
|
|
|
// Source represents a data source for a select statement.
|
|
// A select statement has one source, but they can be one of a table ref, a join,
|
|
// another select statement or any of the above parenthesiszed. For join operators, the Source
|
|
// can form a graph, with the join terms being themselves a Source.
|
|
type Source interface {
|
|
Node
|
|
source()
|
|
SourceFromAlias(alias string) Source
|
|
|
|
// get the possible output columns from the source
|
|
PossibleOutputColumns() []*SourceOutputColumn
|
|
|
|
// find output columns by name
|
|
OutputColumnNamed(name string) (*SourceOutputColumn, error)
|
|
OutputColumnQualifierNamed(qualifier string, name string) (*SourceOutputColumn, error)
|
|
}
|
|
|
|
func (*JoinClause) source() {}
|
|
func (*ParenSource) source() {}
|
|
func (*QualifiedTableName) source() {}
|
|
func (*TableValuedFunction) 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))
|
|
}
|
|
}
|
|
|
|
// SourceList returns a list of sources starting from a source.
|
|
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
|
|
}
|
|
|
|
// 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 ShowDatabasesStatement struct {
|
|
Show Pos // position of SHOW
|
|
Databases Pos // position of DATABASES
|
|
}
|
|
|
|
// String returns the string representation of the statement.
|
|
func (s *ShowDatabasesStatement) String() string {
|
|
return "SHOW DATABASES"
|
|
}
|
|
|
|
// String returns the string representation of the statement.
|
|
func (s *ShowDatabasesStatement) Clone() *ShowDatabasesStatement {
|
|
o := *s
|
|
return &o
|
|
}
|
|
|
|
type ShowTablesStatement struct {
|
|
Show Pos // position of SHOW
|
|
Tables Pos // position of TABLES
|
|
}
|
|
|
|
// String returns the string representation of the statement.
|
|
func (s *ShowTablesStatement) String() string {
|
|
return "SHOW TABLES"
|
|
}
|
|
|
|
func (s *ShowTablesStatement) Clone() *ShowTablesStatement {
|
|
other := *s
|
|
return &other
|
|
}
|
|
|
|
type ShowColumnsStatement struct {
|
|
Show Pos // position of SHOW
|
|
Columns Pos // position of COLUMNS
|
|
From Pos // position of FROM
|
|
TableName *Ident // name of table
|
|
}
|
|
|
|
// String returns the string representation of the statement.
|
|
func (s *ShowColumnsStatement) String() string {
|
|
var buf bytes.Buffer
|
|
buf.WriteString("SHOW COLUMNS ")
|
|
if s.TableName != nil {
|
|
buf.WriteString("FROM")
|
|
fmt.Fprintf(&buf, " %s", s.TableName.String())
|
|
}
|
|
return buf.String()
|
|
}
|
|
|
|
func (s *ShowColumnsStatement) Clone() *ShowColumnsStatement {
|
|
other := *s
|
|
return &other
|
|
}
|
|
|
|
type ShowCreateTableStatement struct {
|
|
Show Pos // position of SHOW
|
|
Create Pos // position of CREATE
|
|
Table Pos // position of CREATE
|
|
TableName *Ident // name of table
|
|
}
|
|
|
|
// String returns the string representation of the statement.
|
|
func (s *ShowCreateTableStatement) String() string {
|
|
var buf bytes.Buffer
|
|
buf.WriteString("SHOW CREATE TABLE")
|
|
if s.TableName != nil {
|
|
fmt.Fprintf(&buf, " %s", s.TableName.String())
|
|
}
|
|
return buf.String()
|
|
}
|
|
|
|
func (s *ShowCreateTableStatement) Clone() *ShowCreateTableStatement {
|
|
other := *s
|
|
other.TableName = s.TableName.Clone()
|
|
return &other
|
|
}
|
|
|
|
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 CreateDatabaseStatement struct {
|
|
Create Pos // position of CREATE keyword
|
|
Database Pos // position of DATABASE keyword
|
|
If Pos // position of IF keyword (optional)
|
|
IfNot Pos // position of NOT keyword (optional)
|
|
IfNotExists Pos // position of EXISTS keyword (optional)
|
|
Name *Ident // database name
|
|
|
|
With Pos // position of WITH keyword
|
|
|
|
Options []DatabaseOption // database options
|
|
}
|
|
|
|
// Clone returns a deep copy of s.
|
|
func (s *CreateDatabaseStatement) Clone() *CreateDatabaseStatement {
|
|
if s == nil {
|
|
return s
|
|
}
|
|
other := *s
|
|
other.Name = s.Name.Clone()
|
|
return &other
|
|
}
|
|
|
|
// String returns the string representation of the statement.
|
|
func (s *CreateDatabaseStatement) String() string {
|
|
var buf bytes.Buffer
|
|
buf.WriteString("CREATE DATABASE")
|
|
if s.IfNotExists.IsValid() {
|
|
buf.WriteString(" IF NOT EXISTS")
|
|
}
|
|
buf.WriteString(" ")
|
|
buf.WriteString(s.Name.String())
|
|
|
|
if s.With.IsValid() {
|
|
buf.WriteString(" WITH")
|
|
for _, opt := range s.Options {
|
|
buf.WriteString(" ")
|
|
buf.WriteString(opt.String())
|
|
}
|
|
}
|
|
|
|
return buf.String()
|
|
}
|
|
|
|
type CreateTableStatement struct {
|
|
Create Pos // position of CREATE keyword
|
|
Table Pos // position of TABLE 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
|
|
Options []TableOption // table options
|
|
}
|
|
|
|
// 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.Options = cloneTableOptions(s.Options)
|
|
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(" ")
|
|
if s.As.IsValid() {
|
|
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(")")
|
|
}
|
|
for i := range s.Options {
|
|
buf.WriteString(" ")
|
|
buf.WriteString(s.Options[i].String())
|
|
}
|
|
|
|
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 DatabaseOption interface {
|
|
Node
|
|
dbOption()
|
|
}
|
|
|
|
func (*UnitsOption) dbOption() {}
|
|
func (*CommentOption) dbOption() {}
|
|
|
|
type UnitsOption struct {
|
|
Units Pos // position of UNITS keyword
|
|
Expr Expr // expression
|
|
}
|
|
|
|
func (o *UnitsOption) String() string {
|
|
var buf bytes.Buffer
|
|
buf.WriteString("UNITS ")
|
|
buf.WriteString(o.Expr.String())
|
|
return buf.String()
|
|
}
|
|
|
|
type TableOption interface {
|
|
Node
|
|
option()
|
|
}
|
|
|
|
func cloneTableOptions(a []TableOption) []TableOption {
|
|
if a == nil {
|
|
return nil
|
|
}
|
|
other := make([]TableOption, len(a))
|
|
for i := range a {
|
|
other[i] = CloneTableOption(a[i])
|
|
}
|
|
return other
|
|
}
|
|
|
|
func CloneTableOption(opt TableOption) TableOption {
|
|
if opt == nil {
|
|
return nil
|
|
}
|
|
|
|
switch cons := opt.(type) {
|
|
case *KeyPartitionsOption:
|
|
return cons.Clone()
|
|
case *CommentOption:
|
|
return cons.Clone()
|
|
default:
|
|
panic(fmt.Sprintf("invalid table option type: %T", cons))
|
|
}
|
|
}
|
|
|
|
func (*KeyPartitionsOption) option() {}
|
|
func (*CommentOption) option() {}
|
|
|
|
type KeyPartitionsOption struct {
|
|
KeyPartitions Pos // position of KEYPARTITIONS keyword
|
|
Expr Expr // expression
|
|
}
|
|
|
|
func (o *KeyPartitionsOption) String() string {
|
|
var buf bytes.Buffer
|
|
buf.WriteString("KEYPARTITIONS ")
|
|
buf.WriteString(o.Expr.String())
|
|
return buf.String()
|
|
}
|
|
|
|
func (o *KeyPartitionsOption) Clone() *KeyPartitionsOption {
|
|
other := *o
|
|
other.Expr = CloneExpr(o.Expr)
|
|
return &other
|
|
}
|
|
|
|
type CommentOption struct {
|
|
Comment Pos // position of COMMENT keyword
|
|
Expr Expr // expression
|
|
}
|
|
|
|
func (o *CommentOption) String() string {
|
|
var buf bytes.Buffer
|
|
buf.WriteString("COMMENT ")
|
|
buf.WriteString(o.Expr.String())
|
|
return buf.String()
|
|
}
|
|
|
|
func (o *CommentOption) Clone() *CommentOption {
|
|
other := *o
|
|
other.Expr = CloneExpr(o.Expr)
|
|
return &other
|
|
}
|
|
|
|
type Constraint interface {
|
|
Node
|
|
constraint()
|
|
}
|
|
|
|
func (*PrimaryKeyConstraint) constraint() {}
|
|
func (*NotNullConstraint) constraint() {}
|
|
func (*UniqueConstraint) constraint() {}
|
|
func (*CheckConstraint) constraint() {}
|
|
func (*DefaultConstraint) constraint() {}
|
|
func (*ForeignKeyConstraint) constraint() {}
|
|
func (*MinConstraint) constraint() {}
|
|
func (*MaxConstraint) constraint() {}
|
|
func (*CacheTypeConstraint) constraint() {}
|
|
func (*TimeUnitConstraint) constraint() {}
|
|
func (*TimeQuantumConstraint) 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()
|
|
case *MaxConstraint:
|
|
return cons.Clone()
|
|
case *MinConstraint:
|
|
return cons.Clone()
|
|
case *CacheTypeConstraint:
|
|
return cons.Clone()
|
|
case *TimeUnitConstraint:
|
|
return cons.Clone()
|
|
case *TimeQuantumConstraint:
|
|
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 MinConstraint struct {
|
|
Min Pos // position of MIN keyword
|
|
Expr Expr // min expression
|
|
}
|
|
|
|
// Clone returns a deep copy of c.
|
|
func (c *MinConstraint) Clone() *MinConstraint {
|
|
if c == nil {
|
|
return c
|
|
}
|
|
other := *c
|
|
other.Expr = CloneExpr(c.Expr)
|
|
return &other
|
|
}
|
|
|
|
// String returns the string representation of the constraint.
|
|
func (c *MinConstraint) String() string {
|
|
var buf bytes.Buffer
|
|
buf.WriteString("MIN ")
|
|
buf.WriteString(c.Expr.String())
|
|
return buf.String()
|
|
}
|
|
|
|
type MaxConstraint struct {
|
|
Max Pos // position of MAX keyword
|
|
Expr Expr // check expression
|
|
}
|
|
|
|
// Clone returns a deep copy of c.
|
|
func (c *MaxConstraint) Clone() *MaxConstraint {
|
|
if c == nil {
|
|
return c
|
|
}
|
|
other := *c
|
|
other.Expr = CloneExpr(c.Expr)
|
|
return &other
|
|
}
|
|
|
|
// String returns the string representation of the constraint.
|
|
func (c *MaxConstraint) String() string {
|
|
var buf bytes.Buffer
|
|
buf.WriteString("MAX ")
|
|
buf.WriteString(c.Expr.String())
|
|
return buf.String()
|
|
}
|
|
|
|
type CacheTypeConstraint struct {
|
|
CacheType Pos // position of CACHETYPE keyword
|
|
CacheTypeValue string
|
|
Size Pos // position of SIZE keyword
|
|
SizeExpr Expr // check expression
|
|
}
|
|
|
|
// Clone returns a deep copy of c.
|
|
func (c *CacheTypeConstraint) Clone() *CacheTypeConstraint {
|
|
if c == nil {
|
|
return c
|
|
}
|
|
other := *c
|
|
other.SizeExpr = CloneExpr(c.SizeExpr)
|
|
return &other
|
|
}
|
|
|
|
// String returns the string representation of the constraint.
|
|
func (c *CacheTypeConstraint) String() string {
|
|
var buf bytes.Buffer
|
|
buf.WriteString("CACHETYPE ")
|
|
buf.WriteString(c.CacheTypeValue)
|
|
if c.Size.IsValid() {
|
|
buf.WriteString(" SIZE ")
|
|
buf.WriteString(c.SizeExpr.String())
|
|
}
|
|
return buf.String()
|
|
}
|
|
|
|
type TimeUnitConstraint struct {
|
|
TimeUnit Pos // position of TIMEUNIT keyword
|
|
Expr Expr // expression
|
|
}
|
|
|
|
// Clone returns a deep copy of c.
|
|
func (c *TimeUnitConstraint) Clone() *TimeUnitConstraint {
|
|
if c == nil {
|
|
return c
|
|
}
|
|
other := *c
|
|
other.Expr = CloneExpr(c.Expr)
|
|
return &other
|
|
}
|
|
|
|
// String returns the string representation of the constraint.
|
|
func (c *TimeUnitConstraint) String() string {
|
|
var buf bytes.Buffer
|
|
buf.WriteString("TIMEUNIT ")
|
|
buf.WriteString(c.Expr.String())
|
|
return buf.String()
|
|
}
|
|
|
|
type TimeQuantumConstraint struct {
|
|
TimeQuantum Pos // position of TIMEQUANTUM keyword
|
|
Expr Expr // expression
|
|
Ttl Pos
|
|
TtlExpr Expr
|
|
}
|
|
|
|
// Clone returns a deep copy of c.
|
|
func (c *TimeQuantumConstraint) Clone() *TimeQuantumConstraint {
|
|
if c == nil {
|
|
return c
|
|
}
|
|
other := *c
|
|
other.Expr = CloneExpr(c.Expr)
|
|
other.TtlExpr = CloneExpr(c.TtlExpr)
|
|
return &other
|
|
}
|
|
|
|
// String returns the string representation of the constraint.
|
|
func (c *TimeQuantumConstraint) String() string {
|
|
var buf bytes.Buffer
|
|
buf.WriteString("TIMEQUANTUM ")
|
|
buf.WriteString(c.Expr.String())
|
|
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 AlterDatabaseStatement struct {
|
|
Alter Pos // position of ALTER keyword
|
|
Database Pos // position of DATABASE keyword
|
|
Name *Ident // database name
|
|
|
|
With Pos // position of WITH keyword
|
|
|
|
Option DatabaseOption
|
|
}
|
|
|
|
// Clone returns a deep copy of s.
|
|
func (s *AlterDatabaseStatement) Clone() *AlterDatabaseStatement {
|
|
if s == nil {
|
|
return nil
|
|
}
|
|
other := *s
|
|
other.Name = other.Name.Clone()
|
|
return &other
|
|
}
|
|
|
|
// String returns the string representation of the statement.
|
|
func (s *AlterDatabaseStatement) String() string {
|
|
var buf bytes.Buffer
|
|
buf.WriteString("ALTER DATABASE ")
|
|
buf.WriteString(s.Name.String())
|
|
|
|
if s.Option != nil {
|
|
buf.WriteString(" WITH ")
|
|
buf.WriteString(s.Option.String())
|
|
}
|
|
return buf.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
|
|
OldColumnName *Ident // old 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
|
|
|
|
Drop Pos // position of ADD keyword
|
|
DropColumn Pos // position of COLUMN keyword after ADD
|
|
DropColumnName *Ident // drop column name
|
|
}
|
|
|
|
// 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.OldColumnName = s.OldColumnName.Clone()
|
|
other.NewColumnName = s.NewColumnName.Clone()
|
|
other.ColumnDef = s.ColumnDef.Clone()
|
|
other.DropColumnName = s.DropColumnName.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.OldColumnName != nil {
|
|
buf.WriteString(" RENAME ")
|
|
if s.RenameColumn.IsValid() {
|
|
buf.WriteString("COLUMN ")
|
|
}
|
|
buf.WriteString(s.OldColumnName.String())
|
|
buf.WriteString(" TO ")
|
|
buf.WriteString(s.NewColumnName.String())
|
|
} else if s.DropColumnName != nil {
|
|
buf.WriteString(" DROP ")
|
|
if s.DropColumn.IsValid() {
|
|
buf.WriteString("COLUMN ")
|
|
}
|
|
buf.WriteString(s.DropColumnName.String())
|
|
} else if s.ColumnDef != nil {
|
|
buf.WriteString(" ADD ")
|
|
if s.AddColumn.IsValid() {
|
|
buf.WriteString("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
|
|
}
|
|
|
|
func (expr *Ident) IsLiteral() bool { return false }
|
|
|
|
func (expr *Ident) DataType() ExprDataType {
|
|
return NewDataTypeVoid()
|
|
}
|
|
|
|
func (expr *Ident) Pos() Pos {
|
|
return expr.NamePos
|
|
}
|
|
|
|
// 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 {
|
|
if i.Quoted {
|
|
return `"` + strings.Replace(i.Name, `"`, `""`, -1) + `"`
|
|
}
|
|
return i.Name
|
|
}
|
|
|
|
// 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
|
|
}
|
|
|
|
// SysVariable represents built-in system variables that can be referenced in
|
|
// the sql for current date, current time and other potential system determinable
|
|
// values. In SQL these system provided data elements are referenced using
|
|
// keywords such as CURRENT_DATE & CURRENT_TIMESTAMP, etc.
|
|
type SysVariable struct {
|
|
NamePos Pos // variable position in sql
|
|
Token Token // parser token mapped to the variable's name/keyword
|
|
}
|
|
|
|
func (*SysVariable) IsLiteral() bool { return false }
|
|
|
|
func (svar *SysVariable) Pos() Pos {
|
|
return svar.NamePos
|
|
}
|
|
|
|
func (svar *SysVariable) Clone() *SysVariable {
|
|
if svar == nil {
|
|
return nil
|
|
}
|
|
other := *svar
|
|
return &other
|
|
}
|
|
func (svar *SysVariable) Name() string {
|
|
return svar.String()
|
|
}
|
|
|
|
func (svar *SysVariable) String() string {
|
|
return svar.Token.String()
|
|
}
|
|
|
|
func (svar *SysVariable) DataType() ExprDataType {
|
|
switch svar.Token {
|
|
case CURRENT_DATE, CURRENT_TIMESTAMP:
|
|
return NewDataTypeTimestamp()
|
|
}
|
|
return nil
|
|
}
|
|
|
|
type Variable struct {
|
|
NamePos Pos // variable position
|
|
Name string // variable name
|
|
VariableIndex int
|
|
VarDataType ExprDataType
|
|
}
|
|
|
|
func (expr *Variable) IsLiteral() bool { return false }
|
|
|
|
func (expr *Variable) DataType() ExprDataType {
|
|
return expr.VarDataType
|
|
}
|
|
|
|
func (expr *Variable) Pos() Pos {
|
|
return expr.NamePos
|
|
}
|
|
|
|
// Clone returns a deep copy of i.
|
|
func (i *Variable) Clone() *Variable {
|
|
if i == nil {
|
|
return nil
|
|
}
|
|
other := *i
|
|
return &other
|
|
}
|
|
|
|
// String returns the string representation of the expression.
|
|
func (i *Variable) String() string {
|
|
return i.Name
|
|
}
|
|
|
|
func (i *Variable) VarName() string {
|
|
return i.Name[1:]
|
|
}
|
|
|
|
type Type struct {
|
|
Name *Ident // type name
|
|
Lparen Pos // position of left paren (optional)
|
|
Precision *IntegerLit // precision (optional)
|
|
Scale *IntegerLit // 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())
|
|
} else if t.Scale != nil {
|
|
// I'm not sure how you're supposed to tell this from the t.Precision case.
|
|
return fmt.Sprintf("%s(%s)", t.Name.Name, t.Scale.String())
|
|
}
|
|
return t.Name.Name
|
|
}
|
|
|
|
type StringLit struct {
|
|
ValuePos Pos // literal position
|
|
Value string // literal value (without quotes)
|
|
IsBlob bool // are we a blob?
|
|
}
|
|
|
|
func (expr *StringLit) IsLiteral() bool { return true }
|
|
|
|
func (expr *StringLit) DataType() ExprDataType {
|
|
return NewDataTypeString()
|
|
}
|
|
|
|
func (expr *StringLit) Pos() Pos {
|
|
return expr.ValuePos
|
|
}
|
|
|
|
func (expr *StringLit) ConvertToTimestamp() *DateLit {
|
|
//try to coerce to a date
|
|
if tm, err := time.ParseInLocation(time.RFC3339Nano, expr.Value, time.UTC); err == nil {
|
|
return &DateLit{ValuePos: expr.ValuePos, Value: tm}
|
|
} else if tm, err := time.ParseInLocation(time.RFC3339, expr.Value, time.UTC); err == nil {
|
|
return &DateLit{ValuePos: expr.ValuePos, Value: tm}
|
|
} else if tm, err := time.ParseInLocation("2006-01-02", expr.Value, time.UTC); err == nil {
|
|
return &DateLit{ValuePos: expr.ValuePos, Value: tm}
|
|
} else {
|
|
return nil
|
|
}
|
|
}
|
|
|
|
// 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 {
|
|
if lit.IsBlob {
|
|
return `x'` + strings.Replace(lit.Value, `'`, `''`, -1) + `'`
|
|
} else {
|
|
return `'` + strings.Replace(lit.Value, `'`, `''`, -1) + `'`
|
|
}
|
|
}
|
|
|
|
type IntegerLit struct {
|
|
ValuePos Pos // literal position
|
|
Value string // literal value
|
|
}
|
|
|
|
func (expr *IntegerLit) IsLiteral() bool { return true }
|
|
|
|
func (expr *IntegerLit) DataType() ExprDataType {
|
|
return NewDataTypeInt()
|
|
}
|
|
|
|
func (expr *IntegerLit) Pos() Pos {
|
|
return expr.ValuePos
|
|
}
|
|
|
|
// Clone returns a deep copy of lit.
|
|
func (lit *IntegerLit) Clone() *IntegerLit {
|
|
if lit == nil {
|
|
return nil
|
|
}
|
|
other := *lit
|
|
return &other
|
|
}
|
|
|
|
// String returns the string representation of the expression.
|
|
func (lit *IntegerLit) String() string {
|
|
return lit.Value
|
|
}
|
|
|
|
type FloatLit struct {
|
|
ValuePos Pos // literal position
|
|
Value string // literal value
|
|
}
|
|
|
|
func (expr *FloatLit) IsLiteral() bool { return true }
|
|
|
|
func (expr *FloatLit) DataType() ExprDataType {
|
|
//how many decimal places do we have on the right of the point?
|
|
scale := NumDecimalPlaces(expr.Value)
|
|
return NewDataTypeDecimal(int64(scale))
|
|
}
|
|
|
|
func (expr *FloatLit) Pos() Pos {
|
|
return expr.ValuePos
|
|
}
|
|
|
|
// Clone returns a deep copy of lit.
|
|
func (lit *FloatLit) Clone() *FloatLit {
|
|
if lit == nil {
|
|
return nil
|
|
}
|
|
other := *lit
|
|
return &other
|
|
}
|
|
|
|
// String returns the string representation of the expression.
|
|
func (lit *FloatLit) String() string {
|
|
return lit.Value
|
|
}
|
|
|
|
type NullLit struct {
|
|
ValuePos Pos
|
|
}
|
|
|
|
func (expr *NullLit) IsLiteral() bool { return true }
|
|
|
|
func (expr *NullLit) DataType() ExprDataType {
|
|
return NewDataTypeVoid()
|
|
}
|
|
|
|
func (expr *NullLit) Pos() Pos {
|
|
return expr.ValuePos
|
|
}
|
|
|
|
// 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
|
|
}
|
|
|
|
func (expr *BoolLit) IsLiteral() bool { return true }
|
|
|
|
func (expr *BoolLit) DataType() ExprDataType {
|
|
return NewDataTypeBool()
|
|
}
|
|
|
|
func (expr *BoolLit) Pos() Pos {
|
|
return expr.ValuePos
|
|
}
|
|
|
|
// 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 DateLit struct {
|
|
ValuePos Pos // literal position
|
|
Value time.Time // literal value
|
|
}
|
|
|
|
func (expr *DateLit) IsLiteral() bool { return true }
|
|
|
|
func (expr *DateLit) DataType() ExprDataType {
|
|
return NewDataTypeTimestamp()
|
|
}
|
|
|
|
func (expr *DateLit) Pos() Pos {
|
|
return expr.ValuePos
|
|
}
|
|
|
|
// Clone returns a deep copy of lit.
|
|
func (lit *DateLit) Clone() *DateLit {
|
|
if lit == nil {
|
|
return nil
|
|
}
|
|
other := *lit
|
|
return &other
|
|
}
|
|
|
|
// String returns the string representation of the Datetime value.
|
|
func (lit *DateLit) String() string {
|
|
return "'" + lit.Value.Format(time.RFC3339) + "'"
|
|
}
|
|
|
|
type UnaryExpr struct {
|
|
OpPos Pos // operation position
|
|
Op Token // operation
|
|
X Expr // target expression
|
|
|
|
ResultDataType ExprDataType
|
|
}
|
|
|
|
func (expr *UnaryExpr) IsLiteral() bool {
|
|
return expr.X.IsLiteral()
|
|
}
|
|
|
|
func (expr *UnaryExpr) DataType() ExprDataType {
|
|
return expr.ResultDataType
|
|
}
|
|
|
|
func (expr *UnaryExpr) Pos() Pos {
|
|
return expr.OpPos
|
|
}
|
|
|
|
// 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()
|
|
case BITNOT:
|
|
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
|
|
|
|
ResultDataType ExprDataType
|
|
}
|
|
|
|
func (expr *BinaryExpr) IsLiteral() bool {
|
|
return expr.X.IsLiteral() && expr.Y.IsLiteral()
|
|
}
|
|
|
|
func (expr *BinaryExpr) DataType() ExprDataType {
|
|
return expr.ResultDataType
|
|
}
|
|
|
|
func (expr *BinaryExpr) Pos() Pos {
|
|
return expr.X.Pos()
|
|
}
|
|
|
|
// 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
|
|
|
|
ResultDataType ExprDataType
|
|
}
|
|
|
|
func (expr *CastExpr) IsLiteral() bool {
|
|
return expr.X.IsLiteral()
|
|
}
|
|
|
|
func (expr *CastExpr) DataType() ExprDataType {
|
|
return expr.ResultDataType
|
|
}
|
|
|
|
func (expr *CastExpr) Pos() Pos {
|
|
return expr.Cast
|
|
}
|
|
|
|
// 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
|
|
|
|
ResultDataType ExprDataType
|
|
}
|
|
|
|
func (expr *CaseExpr) IsLiteral() bool { return false }
|
|
|
|
func (expr *CaseExpr) DataType() ExprDataType {
|
|
return expr.ResultDataType
|
|
}
|
|
|
|
func (expr *CaseExpr) Pos() Pos {
|
|
return expr.Case
|
|
}
|
|
|
|
// 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
|
|
}
|
|
|
|
func (expr *CaseBlock) IsLiteral() bool { return false }
|
|
|
|
func (expr *CaseBlock) DataType() ExprDataType {
|
|
return expr.Body.DataType()
|
|
}
|
|
|
|
func (expr *CaseBlock) Pos() Pos {
|
|
return expr.When
|
|
}
|
|
|
|
// 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 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
|
|
}
|
|
|
|
func (expr *Exists) IsLiteral() bool { return false }
|
|
|
|
func (expr *Exists) DataType() ExprDataType {
|
|
return NewDataTypeBool()
|
|
}
|
|
|
|
func (expr *Exists) Pos() Pos {
|
|
if expr.Not.IsValid() {
|
|
return expr.Not
|
|
}
|
|
return expr.Exists
|
|
}
|
|
|
|
// 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
|
|
}
|
|
|
|
func (expr *ExprList) IsLiteral() bool {
|
|
for _, e := range expr.Exprs {
|
|
if !e.IsLiteral() {
|
|
return false
|
|
}
|
|
}
|
|
return true
|
|
}
|
|
|
|
func (expr *ExprList) DataType() ExprDataType {
|
|
return NewDataTypeVoid()
|
|
}
|
|
|
|
func (expr *ExprList) Pos() Pos {
|
|
return expr.Lparen
|
|
}
|
|
|
|
// 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
|
|
|
|
ResultDataType ExprDataType
|
|
}
|
|
|
|
func (expr *Range) IsLiteral() bool { return false }
|
|
|
|
func (expr *Range) DataType() ExprDataType {
|
|
return expr.ResultDataType
|
|
}
|
|
|
|
func (expr *Range) Pos() Pos {
|
|
return expr.X.Pos()
|
|
}
|
|
|
|
// 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
|
|
ColumnIndex int
|
|
|
|
// Set by the planner; not at parse-time
|
|
RefDataType ExprDataType
|
|
}
|
|
|
|
func (expr *QualifiedRef) IsLiteral() bool { return false }
|
|
|
|
func (expr *QualifiedRef) DataType() ExprDataType {
|
|
return expr.RefDataType
|
|
}
|
|
|
|
func (expr *QualifiedRef) Pos() Pos {
|
|
return expr.Table.Pos()
|
|
}
|
|
|
|
// 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
|
|
|
|
ResultDataType ExprDataType
|
|
}
|
|
|
|
func (expr *Call) IsLiteral() bool { return false }
|
|
|
|
func (expr *Call) DataType() ExprDataType {
|
|
return expr.ResultDataType
|
|
}
|
|
|
|
func (expr *Call) Pos() Pos {
|
|
return expr.Name.Pos()
|
|
}
|
|
|
|
// 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.Y = 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 DropDatabaseStatement struct {
|
|
Drop Pos // position of DROP keyword
|
|
Database Pos // position of DATABASE keyword
|
|
If Pos // position of IF keyword
|
|
IfExists Pos // position of EXISTS keyword after IF
|
|
Name *Ident // database name
|
|
}
|
|
|
|
// Clone returns a deep copy of s.
|
|
func (s *DropDatabaseStatement) Clone() *DropDatabaseStatement {
|
|
if s == nil {
|
|
return nil
|
|
}
|
|
other := *s
|
|
other.Name = s.Name.Clone()
|
|
return &other
|
|
}
|
|
|
|
// String returns the string representation of the statement.
|
|
func (s *DropDatabaseStatement) String() string {
|
|
var buf bytes.Buffer
|
|
buf.WriteString("DROP DATABASE")
|
|
if s.IfExists.IsValid() {
|
|
buf.WriteString(" IF EXISTS")
|
|
}
|
|
fmt.Fprintf(&buf, " %s", s.Name.String())
|
|
return buf.String()
|
|
}
|
|
|
|
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 // table 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
|
|
// TODO(pok) - we'll do this later - see note in parseCompileView()
|
|
// 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 AlterViewStatement struct {
|
|
Alter Pos // position of CREATE keyword
|
|
View Pos // position of VIEW keyword
|
|
Name *Ident // view name
|
|
|
|
// TODO(pok) - we'll do this later - see note in parseCompileView()
|
|
// 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 *AlterViewStatement) Clone() *AlterViewStatement {
|
|
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 *AlterViewStatement) String() string {
|
|
var buf bytes.Buffer
|
|
buf.WriteString("ALTER VIEW")
|
|
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 DropModelStatement struct {
|
|
Drop Pos // position of DROP keyword
|
|
Model Pos // position of MODEL 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 *DropModelStatement) Clone() *DropModelStatement {
|
|
if s == nil {
|
|
return nil
|
|
}
|
|
other := *s
|
|
other.Name = s.Name.Clone()
|
|
return &other
|
|
}
|
|
|
|
// String returns the string representation of the statement.
|
|
func (s *DropModelStatement) String() string {
|
|
var buf bytes.Buffer
|
|
buf.WriteString("DROP MODEL")
|
|
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 FunctionOptionDefinition struct {
|
|
Name *Ident // option name
|
|
OptionExpr Expr // option expression
|
|
}
|
|
|
|
type ParameterDefinition struct {
|
|
Name *Variable // parameter name
|
|
Type *Type // data type
|
|
}
|
|
|
|
type CreateFunctionStatement struct {
|
|
Create Pos // position of CREATE keyword
|
|
Function Pos // position of FUNCTION 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
|
|
|
|
Lparen Pos // position of parameter LParen
|
|
Parameters []*ParameterDefinition // parameters
|
|
Rparen Pos // position of parameter RParen
|
|
|
|
Returns Pos // position of RETURNS keyword
|
|
ReturnType *Type // return def
|
|
|
|
With Pos // position of WITH keyword
|
|
Options []*FunctionOptionDefinition // options
|
|
|
|
As Pos // position of AS keyword
|
|
|
|
Begin Pos // position of BEGIN keyword
|
|
Body []Statement // function body
|
|
End Pos // position of END keyword
|
|
}
|
|
|
|
// Clone returns a deep copy of s.
|
|
func (s *CreateFunctionStatement) Clone() *CreateFunctionStatement {
|
|
if s == nil {
|
|
return nil
|
|
}
|
|
other := *s
|
|
other.Name = s.Name.Clone()
|
|
other.Body = cloneStatements(s.Body)
|
|
return &other
|
|
}
|
|
|
|
// String returns the string representation of the statement.
|
|
func (s *CreateFunctionStatement) String() string {
|
|
var buf bytes.Buffer
|
|
buf.WriteString("CREATE FUNCTION")
|
|
if s.IfNotExists.IsValid() {
|
|
buf.WriteString(" IF NOT EXISTS")
|
|
}
|
|
fmt.Fprintf(&buf, " %s", s.Name.String())
|
|
|
|
if len(s.Parameters) > 0 {
|
|
buf.WriteString(" (")
|
|
for idx, p := range s.Parameters {
|
|
if idx > 0 {
|
|
buf.WriteString(", ")
|
|
}
|
|
fmt.Fprintf(&buf, "%s %s", p.Name.Name, p.Type.Name)
|
|
}
|
|
buf.WriteString(")")
|
|
}
|
|
|
|
buf.WriteString(" RETURNS ")
|
|
fmt.Fprintf(&buf, "%s", s.ReturnType.String())
|
|
|
|
if s.With.IsValid() {
|
|
buf.WriteString(" WITH ")
|
|
if len(s.Options) > 0 {
|
|
buf.WriteString(" (")
|
|
for idx, p := range s.Options {
|
|
if idx > 0 {
|
|
buf.WriteString(", ")
|
|
}
|
|
fmt.Fprintf(&buf, "%s %s", p.Name.Name, p.OptionExpr.String())
|
|
}
|
|
buf.WriteString(")")
|
|
}
|
|
}
|
|
|
|
buf.WriteString(" AS BEGIN")
|
|
for i := range s.Body {
|
|
fmt.Fprintf(&buf, " %s;", s.Body[i].String())
|
|
}
|
|
buf.WriteString(" END")
|
|
|
|
return buf.String()
|
|
}
|
|
|
|
type DropFunctionStatement struct {
|
|
Drop Pos // position of DROP keyword
|
|
Function Pos // position of FUNCTION 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 *DropFunctionStatement) Clone() *DropFunctionStatement {
|
|
if s == nil {
|
|
return nil
|
|
}
|
|
other := *s
|
|
other.Name = s.Name.Clone()
|
|
return &other
|
|
}
|
|
|
|
func (s *DropFunctionStatement) String() string {
|
|
var buf bytes.Buffer
|
|
buf.WriteString("DROP FUNCTION")
|
|
if s.IfExists.IsValid() {
|
|
buf.WriteString(" IF EXISTS")
|
|
}
|
|
fmt.Fprintf(&buf, " %s", s.Name.String())
|
|
return buf.String()
|
|
}
|
|
|
|
type ReturnStatement struct {
|
|
Return Pos // position of RETURN keyword
|
|
ReturnExpr Expr // what we are returning
|
|
}
|
|
|
|
// Clone returns a deep copy of s.
|
|
func (s *ReturnStatement) Clone() *ReturnStatement {
|
|
if s == nil {
|
|
return nil
|
|
}
|
|
other := *s
|
|
other.ReturnExpr = CloneExpr(s.ReturnExpr)
|
|
return &other
|
|
}
|
|
|
|
func (s *ReturnStatement) String() string {
|
|
var buf bytes.Buffer
|
|
buf.WriteString("RETURN")
|
|
fmt.Fprintf(&buf, " %s", s.ReturnExpr.String())
|
|
return buf.String()
|
|
}
|
|
|
|
type ModelOptionDefinition struct {
|
|
Name *Ident // option name
|
|
OptionExpr Expr // option expression
|
|
}
|
|
|
|
type CreateModelStatement struct {
|
|
Create Pos // position of CREATE keyword
|
|
Model Pos // position of MODEL 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 // model name
|
|
With Pos // position of WITH keyword
|
|
|
|
Options []*ModelOptionDefinition // options
|
|
|
|
As Pos // position of AS keyword
|
|
|
|
ModelQuery *SelectStatement // model query
|
|
}
|
|
|
|
// Clone returns a deep copy of s.
|
|
func (s *CreateModelStatement) Clone() *CreateModelStatement {
|
|
if s == nil {
|
|
return nil
|
|
}
|
|
other := *s
|
|
other.Name = s.Name.Clone()
|
|
other.ModelQuery = s.ModelQuery.Clone()
|
|
return &other
|
|
}
|
|
|
|
// String returns the string representation of the statement.
|
|
func (s *CreateModelStatement) String() string {
|
|
var buf bytes.Buffer
|
|
buf.WriteString("CREATE MODEL")
|
|
if s.IfNotExists.IsValid() {
|
|
buf.WriteString(" IF NOT EXISTS")
|
|
}
|
|
fmt.Fprintf(&buf, " %s", s.Name.String())
|
|
|
|
if len(s.Options) > 0 {
|
|
buf.WriteString(" (")
|
|
for idx, p := range s.Options {
|
|
if idx > 0 {
|
|
buf.WriteString(", ")
|
|
}
|
|
fmt.Fprintf(&buf, "%s %s", p.Name.Name, p.OptionExpr.String())
|
|
}
|
|
buf.WriteString(")")
|
|
}
|
|
|
|
buf.WriteString(" AS ")
|
|
buf.WriteString(s.ModelQuery.String())
|
|
|
|
return buf.String()
|
|
}
|
|
|
|
type BulkInsertMapDefinition struct {
|
|
Name *Ident // map name
|
|
Type *Type // data type
|
|
MapExpr Expr
|
|
}
|
|
|
|
// Clone returns a deep copy of d.
|
|
func (d *BulkInsertMapDefinition) Clone() *BulkInsertMapDefinition {
|
|
if d == nil {
|
|
return d
|
|
}
|
|
other := *d
|
|
other.Name = d.Name.Clone()
|
|
other.Type = d.Type.Clone()
|
|
//other.MapExpr = d.MapExpr.Clone()
|
|
return &other
|
|
}
|
|
|
|
// String returns the string representation of the statement.
|
|
func (c *BulkInsertMapDefinition) String() string {
|
|
var buf bytes.Buffer
|
|
buf.WriteString(c.MapExpr.String())
|
|
buf.WriteString(" ")
|
|
buf.WriteString(c.Type.String())
|
|
return buf.String()
|
|
}
|
|
|
|
type BulkInsertStatement struct {
|
|
Bulk Pos // position of BULK keyword
|
|
Insert Pos // position of INSERT keyword
|
|
Replace Pos // position of REPLACE keyword
|
|
Into Pos // position of INTO keyword
|
|
|
|
Table *Ident // table name
|
|
|
|
ColumnsLparen Pos // position of column list left paren
|
|
Columns []*Ident // optional column list
|
|
ColumnsRparen Pos // position of column list right paren
|
|
|
|
Map Pos // position of MAP keyword
|
|
MapLparen Pos // position of column list left paren
|
|
MapList []*BulkInsertMapDefinition // source to column map
|
|
MapRparen Pos // position of column list right paren
|
|
|
|
Transform Pos // position of MAP keyword
|
|
TransformLparen Pos // position of column list left paren
|
|
TransformList []Expr // source to column map
|
|
TransformRparen Pos // position of column list right paren
|
|
|
|
From Pos // position of FROM keyword
|
|
DataSource Expr // data source
|
|
With Pos // position of WITH keyword
|
|
BatchSize Expr
|
|
RowsLimit Expr
|
|
Format Expr
|
|
Input Expr
|
|
HeaderRow Expr // has header row (that needs to be skipped)
|
|
AllowMissingValues Expr // allows missing values
|
|
}
|
|
|
|
func (s *BulkInsertStatement) String() string {
|
|
var buf bytes.Buffer
|
|
buf.WriteString("BULK ")
|
|
if s.Replace.IsValid() {
|
|
buf.WriteString("REPLACE")
|
|
} else {
|
|
buf.WriteString("INSERT")
|
|
}
|
|
buf.WriteString(" INTO ")
|
|
fmt.Fprintf(&buf, " %s", s.Table.String())
|
|
|
|
if s.Columns != nil {
|
|
buf.WriteString("(")
|
|
|
|
for i, col := range s.Columns {
|
|
if i != 0 {
|
|
buf.WriteString(", ")
|
|
}
|
|
buf.WriteString(col.String())
|
|
}
|
|
|
|
buf.WriteString(")")
|
|
}
|
|
buf.WriteString(" MAP ")
|
|
buf.WriteString("(")
|
|
for i, m := range s.MapList {
|
|
if i != 0 {
|
|
buf.WriteString(", ")
|
|
}
|
|
buf.WriteString(m.String())
|
|
}
|
|
buf.WriteString(")")
|
|
if s.TransformList != nil {
|
|
buf.WriteString(" TRANSFORM ")
|
|
buf.WriteString("(")
|
|
|
|
for i, t := range s.TransformList {
|
|
if i != 0 {
|
|
buf.WriteString(", ")
|
|
}
|
|
buf.WriteString(t.String())
|
|
}
|
|
|
|
buf.WriteString(")")
|
|
}
|
|
|
|
buf.WriteString(" FROM ")
|
|
fmt.Fprintf(&buf, " %s", s.DataSource.String())
|
|
buf.WriteString(" WITH")
|
|
|
|
if s.Format != nil {
|
|
buf.WriteString(" FORMAT ")
|
|
buf.WriteString(s.Format.String())
|
|
}
|
|
|
|
if s.Input != nil {
|
|
buf.WriteString(" INPUT ")
|
|
buf.WriteString(s.Input.String())
|
|
}
|
|
|
|
if s.HeaderRow != nil {
|
|
buf.WriteString(" HEADER_ROW ")
|
|
}
|
|
|
|
if s.BatchSize != nil {
|
|
buf.WriteString(" BATCHSIZE ")
|
|
buf.WriteString(s.BatchSize.String())
|
|
}
|
|
|
|
if s.RowsLimit != nil {
|
|
buf.WriteString(" ROWSLIMIT ")
|
|
buf.WriteString(s.RowsLimit.String())
|
|
}
|
|
|
|
if s.AllowMissingValues != nil {
|
|
buf.WriteString(" ALLOW_MISSING_VALUES ")
|
|
}
|
|
return buf.String()
|
|
}
|
|
|
|
func (s *BulkInsertStatement) Clone() *BulkInsertStatement {
|
|
if s == nil {
|
|
return nil
|
|
}
|
|
other := *s
|
|
other.Table = s.Table.Clone()
|
|
other.Columns = cloneIdents(s.Columns)
|
|
other.TransformList = cloneExprs(s.TransformList)
|
|
other.DataSource = CloneExpr(s.DataSource)
|
|
other.BatchSize = CloneExpr(s.BatchSize)
|
|
other.RowsLimit = CloneExpr(s.RowsLimit)
|
|
other.Format = CloneExpr(s.Format)
|
|
other.Input = CloneExpr(s.Input)
|
|
other.HeaderRow = CloneExpr(s.HeaderRow)
|
|
other.AllowMissingValues = CloneExpr(s.AllowMissingValues)
|
|
other.MapList = cloneBulkInsertMap(s.MapList)
|
|
return &other
|
|
}
|
|
|
|
func cloneBulkInsertMap(s []*BulkInsertMapDefinition) []*BulkInsertMapDefinition {
|
|
other := make([]*BulkInsertMapDefinition, len(s))
|
|
for i := range s {
|
|
other[i] = s[i].Clone()
|
|
}
|
|
return other
|
|
}
|
|
|
|
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
|
|
TupleList []*ExprList // multiple tuples
|
|
|
|
// 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.TupleList = cloneExprLists(s.TupleList)
|
|
//other.Select = s.Select.Clone()
|
|
//other.UpsertClause = s.UpsertClause.Clone()
|
|
return &other
|
|
}
|
|
|
|
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, tuple := range s.TupleList {
|
|
if i != 0 {
|
|
buf.WriteString(",")
|
|
}
|
|
buf.WriteString(" (")
|
|
for j, expr := range tuple.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
|
|
TableName *QualifiedTableName // the name of the table we are deleting from
|
|
Source Source // source for the delete
|
|
|
|
Where Pos // position of WHERE keyword
|
|
WhereExpr Expr // conditional 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.Source = CloneSource(s.Source)
|
|
other.WhereExpr = CloneExpr(s.WhereExpr)
|
|
return &other
|
|
}
|
|
|
|
// String returns the string representation of the clause.
|
|
func (s *DeleteStatement) String() string {
|
|
var buf bytes.Buffer
|
|
|
|
fmt.Fprintf(&buf, "DELETE FROM %s", s.TableName.String())
|
|
if s.WhereExpr != nil {
|
|
fmt.Fprintf(&buf, " WHERE %s", s.WhereExpr.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 CopyStatement struct {
|
|
Copy Pos // position of COPY keyword
|
|
Source Source // source table
|
|
To Pos // position of TO keyword
|
|
TargetName *Ident // target table name
|
|
Where Pos // position of WHERE keyword
|
|
WhereExpr Expr // where clause expression
|
|
With Pos // position of WITH keyword
|
|
|
|
Url Expr // url for target server
|
|
ApiKey Expr // apikey for target server
|
|
}
|
|
|
|
func (c *CopyStatement) Clone() *CopyStatement {
|
|
if c == nil {
|
|
return nil
|
|
}
|
|
other := *c
|
|
other.Source = CloneSource(c.Source)
|
|
other.TargetName = c.TargetName.Clone()
|
|
other.WhereExpr = CloneExpr(c.WhereExpr)
|
|
other.Url = CloneExpr(c.Url)
|
|
other.ApiKey = CloneExpr(c.ApiKey)
|
|
return &other
|
|
}
|
|
|
|
func (c *CopyStatement) String() string {
|
|
var buf bytes.Buffer
|
|
|
|
fmt.Fprintf(&buf, "COPY %s to %s", c.Source.String(), c.TargetName.String())
|
|
if c.WhereExpr != nil {
|
|
fmt.Fprintf(&buf, " WHERE %s", c.WhereExpr.String())
|
|
}
|
|
if c.With.IsValid() {
|
|
fmt.Fprintf(&buf, " WITH")
|
|
if c.Url != nil {
|
|
fmt.Fprintf(&buf, " URL %s", c.Url.String())
|
|
}
|
|
if c.ApiKey != nil {
|
|
fmt.Fprintf(&buf, " APIKEY %s", c.Url.String())
|
|
}
|
|
}
|
|
return buf.String()
|
|
}
|
|
|
|
type PredictStatement struct {
|
|
Predict Pos // position of PREDICT keyword
|
|
Using Pos // position of USING keyword
|
|
ModelName *Ident // model name
|
|
|
|
InputQuery *SelectStatement // input query
|
|
}
|
|
|
|
func (c *PredictStatement) Clone() *PredictStatement {
|
|
if c == nil {
|
|
return nil
|
|
}
|
|
other := *c
|
|
other.ModelName = c.ModelName.Clone()
|
|
other.InputQuery = c.InputQuery.Clone()
|
|
return &other
|
|
}
|
|
|
|
func (c *PredictStatement) String() string {
|
|
var buf bytes.Buffer
|
|
|
|
fmt.Fprintf(&buf, "PREDICT USING %s", c.ModelName.String())
|
|
fmt.Fprintf(&buf, " %s", c.InputQuery.String())
|
|
return buf.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
|
|
|
|
Top Pos // position of TOP keyword
|
|
TopN Pos // position of TOPN keyword
|
|
TopExpr Expr // TOP expr
|
|
|
|
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 expr
|
|
}
|
|
|
|
// 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.TopExpr = CloneExpr(s.TopExpr)
|
|
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)
|
|
return &other
|
|
}
|
|
|
|
func (expr *SelectStatement) IsLiteral() bool { 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
|
|
}
|
|
|
|
func (s *SelectStatement) DataType() ExprDataType {
|
|
return nil
|
|
}
|
|
|
|
func (s *SelectStatement) Pos() Pos {
|
|
return s.Select
|
|
}
|
|
|
|
// 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(" ")
|
|
}
|
|
|
|
buf.WriteString("SELECT ")
|
|
if s.Distinct.IsValid() {
|
|
buf.WriteString("DISTINCT ")
|
|
}
|
|
if s.Top.IsValid() {
|
|
fmt.Fprintf(&buf, "TOP(%s) ", s.TopExpr.String())
|
|
}
|
|
if s.TopN.IsValid() {
|
|
fmt.Fprintf(&buf, "TOPN(%s) ", s.TopExpr.String())
|
|
}
|
|
|
|
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())
|
|
}
|
|
}
|
|
|
|
if s.Limit.IsValid() {
|
|
fmt.Fprintf(&buf, " LIMIT %s", s.LimitExpr.String())
|
|
}
|
|
|
|
return buf.String()
|
|
}
|
|
|
|
func (c *SelectStatement) SourceFromAlias(alias string) Source {
|
|
return nil
|
|
}
|
|
|
|
func (c *SelectStatement) PossibleOutputColumns() []*SourceOutputColumn {
|
|
result := make([]*SourceOutputColumn, 0)
|
|
// populate the output columns from the columns in the select list
|
|
for idx, col := range c.Columns {
|
|
soc := &SourceOutputColumn{
|
|
TableName: "",
|
|
ColumnName: col.Name(),
|
|
ColumnIndex: idx,
|
|
Datatype: col.Expr.DataType(),
|
|
}
|
|
result = append(result, soc)
|
|
}
|
|
return result
|
|
}
|
|
|
|
func (c *SelectStatement) OutputColumnNamed(name string) (*SourceOutputColumn, error) {
|
|
ocs := c.PossibleOutputColumns()
|
|
|
|
for _, oc := range ocs {
|
|
if strings.EqualFold(oc.ColumnName, name) {
|
|
return oc, nil
|
|
}
|
|
}
|
|
return nil, nil
|
|
}
|
|
|
|
func (c *SelectStatement) OutputColumnQualifierNamed(qualifier string, name string) (*SourceOutputColumn, error) {
|
|
return nil, nil
|
|
}
|
|
|
|
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 *Ident:
|
|
return IdentName(expr)
|
|
case *QualifiedRef:
|
|
return IdentName(expr.Column)
|
|
default:
|
|
return ""
|
|
}
|
|
}
|
|
|
|
func (expr *ResultColumn) IsLiteral() bool { return false }
|
|
|
|
// 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 {
|
|
if c.As.IsValid() {
|
|
return fmt.Sprintf("%s AS %s", c.Expr.String(), c.Alias.String())
|
|
} else {
|
|
return fmt.Sprintf("%s %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
|
|
OutputColumns []*SourceOutputColumn // output columns - populated during analysis
|
|
}
|
|
|
|
// 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)
|
|
}
|
|
|
|
func (n *QualifiedTableName) MatchesTablenameOrAlias(match string) bool {
|
|
return strings.EqualFold(IdentName(n.Alias), match) || strings.EqualFold(IdentName(n.Name), match)
|
|
}
|
|
|
|
// 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 {
|
|
if n.As.IsValid() {
|
|
buf.WriteString(" AS")
|
|
}
|
|
fmt.Fprintf(&buf, " %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()
|
|
}
|
|
|
|
func (c *QualifiedTableName) SourceFromAlias(alias string) Source {
|
|
if strings.EqualFold(IdentName(c.Alias), alias) {
|
|
return c
|
|
}
|
|
if strings.EqualFold(IdentName(c.Name), alias) {
|
|
return c
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (c *QualifiedTableName) PossibleOutputColumns() []*SourceOutputColumn {
|
|
return c.OutputColumns
|
|
}
|
|
|
|
func (c *QualifiedTableName) OutputColumnNamed(name string) (*SourceOutputColumn, error) {
|
|
for _, oc := range c.OutputColumns {
|
|
if strings.EqualFold(oc.ColumnName, name) {
|
|
return oc, nil
|
|
}
|
|
}
|
|
return nil, nil
|
|
}
|
|
|
|
func (c *QualifiedTableName) OutputColumnQualifierNamed(qualifier string, name string) (*SourceOutputColumn, error) {
|
|
if strings.EqualFold(IdentName(c.Alias), qualifier) || strings.EqualFold(IdentName(c.Name), qualifier) {
|
|
return c.OutputColumnNamed(name)
|
|
}
|
|
return nil, nil
|
|
}
|
|
|
|
type TableValuedFunction struct {
|
|
Name *Ident // table name
|
|
As Pos // position of AS keyword
|
|
Alias *Ident // optional table alias
|
|
Call *Call // call
|
|
OutputColumns []*SourceOutputColumn // output columns - populated during analysis
|
|
}
|
|
|
|
// TableName returns the name used to identify n.
|
|
// Returns the alias, if one is specified. Otherwise returns the name.
|
|
func (n *TableValuedFunction) TableName() string {
|
|
if s := IdentName(n.Alias); s != "" {
|
|
return s
|
|
}
|
|
return IdentName(n.Name)
|
|
}
|
|
|
|
func (n *TableValuedFunction) MatchesTablenameOrAlias(match string) bool {
|
|
return strings.EqualFold(IdentName(n.Alias), match) || strings.EqualFold(IdentName(n.Name), match)
|
|
}
|
|
|
|
// Clone returns a deep copy of n.
|
|
func (n *TableValuedFunction) Clone() *TableValuedFunction {
|
|
if n == nil {
|
|
return nil
|
|
}
|
|
other := *n
|
|
other.Name = n.Name.Clone()
|
|
other.Alias = n.Alias.Clone()
|
|
return &other
|
|
}
|
|
|
|
// String returns the string representation of the table name.
|
|
func (n *TableValuedFunction) String() string {
|
|
var buf bytes.Buffer
|
|
buf.WriteString(n.Name.String())
|
|
if n.Alias != nil {
|
|
if n.As.IsValid() {
|
|
buf.WriteString(" AS")
|
|
}
|
|
fmt.Fprintf(&buf, " %s", n.Alias.String())
|
|
}
|
|
|
|
return buf.String()
|
|
}
|
|
|
|
func (c *TableValuedFunction) SourceFromAlias(alias string) Source {
|
|
if strings.EqualFold(IdentName(c.Alias), alias) {
|
|
return c
|
|
}
|
|
if strings.EqualFold(IdentName(c.Name), alias) {
|
|
return c
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (c *TableValuedFunction) PossibleOutputColumns() []*SourceOutputColumn {
|
|
return c.OutputColumns
|
|
}
|
|
|
|
func (c *TableValuedFunction) OutputColumnNamed(name string) (*SourceOutputColumn, error) {
|
|
for _, oc := range c.OutputColumns {
|
|
if strings.EqualFold(oc.ColumnName, name) {
|
|
return oc, nil
|
|
}
|
|
}
|
|
return nil, nil
|
|
}
|
|
|
|
func (c *TableValuedFunction) OutputColumnQualifierNamed(qualifier string, name string) (*SourceOutputColumn, error) {
|
|
if strings.EqualFold(IdentName(c.Alias), qualifier) || strings.EqualFold(IdentName(c.Name), qualifier) {
|
|
return c.OutputColumnNamed(name)
|
|
}
|
|
return nil, nil
|
|
}
|
|
|
|
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())
|
|
}
|
|
|
|
func (c *ParenSource) SourceFromAlias(alias string) Source {
|
|
if strings.EqualFold(IdentName(c.Alias), alias) {
|
|
return c
|
|
}
|
|
return c.X.SourceFromAlias(alias)
|
|
}
|
|
|
|
func (c *ParenSource) PossibleOutputColumns() []*SourceOutputColumn {
|
|
aliasName := IdentName(c.Alias)
|
|
poc := c.X.PossibleOutputColumns()
|
|
for _, pc := range poc {
|
|
pc.TableName = aliasName
|
|
}
|
|
return poc
|
|
}
|
|
|
|
func (c *ParenSource) OutputColumnNamed(name string) (*SourceOutputColumn, error) {
|
|
return c.X.OutputColumnNamed(name)
|
|
}
|
|
|
|
func (c *ParenSource) OutputColumnQualifierNamed(qualifier string, name string) (*SourceOutputColumn, error) {
|
|
if strings.EqualFold(IdentName(c.Alias), qualifier) {
|
|
return c.OutputColumnNamed(name)
|
|
}
|
|
return nil, nil
|
|
}
|
|
|
|
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)
|
|
other.Operator = c.Operator.Clone()
|
|
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()
|
|
}
|
|
|
|
func (c *JoinClause) PossibleOutputColumns() []*SourceOutputColumn {
|
|
poc := make([]*SourceOutputColumn, 0)
|
|
poc = append(poc, c.X.PossibleOutputColumns()...)
|
|
poc = append(poc, c.Y.PossibleOutputColumns()...)
|
|
return poc
|
|
|
|
}
|
|
|
|
func (c *JoinClause) OutputColumnNamed(name string) (*SourceOutputColumn, error) {
|
|
if col, err := c.X.OutputColumnNamed(name); err != nil {
|
|
return nil, err
|
|
} else if col != nil {
|
|
return col, nil
|
|
}
|
|
|
|
if col, err := c.Y.OutputColumnNamed(name); err != nil {
|
|
return nil, err
|
|
} else if col != nil {
|
|
return col, nil
|
|
}
|
|
|
|
return nil, nil
|
|
}
|
|
|
|
func (c *JoinClause) OutputColumnQualifierNamed(qualifier string, name string) (*SourceOutputColumn, error) {
|
|
if col, err := c.X.OutputColumnQualifierNamed(qualifier, name); err != nil {
|
|
return nil, err
|
|
} else if col != nil {
|
|
return col, nil
|
|
}
|
|
|
|
if col, err := c.Y.OutputColumnQualifierNamed(qualifier, name); err != nil {
|
|
return nil, err
|
|
} else if col != nil {
|
|
return col, nil
|
|
}
|
|
|
|
return nil, nil
|
|
}
|
|
|
|
func (c *JoinClause) SourceFromAlias(alias string) Source {
|
|
if src := c.X.SourceFromAlias(alias); src != nil {
|
|
return src
|
|
}
|
|
if src := c.Y.SourceFromAlias(alias); src != nil {
|
|
return src
|
|
}
|
|
return nil
|
|
}
|
|
|
|
type JoinOperator struct {
|
|
Comma Pos // position of comma
|
|
Left Pos // position of LEFT keyword
|
|
Right Pos // position of RIGHT keyword
|
|
Full Pos // position of FULL keyword
|
|
Outer Pos // position of OUTER keyword
|
|
Inner Pos // position of INNER keyword
|
|
// Cross Pos // position of CROSS keyword // TODO(pok) - add cross back when we do it
|
|
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.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(")")
|
|
}
|
|
if cte.As.IsValid() {
|
|
buf.WriteString(" AS")
|
|
}
|
|
fmt.Fprintf(&buf, " (%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
|
|
}
|
|
|
|
func (expr *ParenExpr) IsLiteral() bool {
|
|
return expr.X.IsLiteral()
|
|
}
|
|
|
|
func (expr *ParenExpr) DataType() ExprDataType {
|
|
return expr.X.DataType()
|
|
}
|
|
|
|
func (expr *ParenExpr) Pos() Pos {
|
|
return expr.Lparen
|
|
}
|
|
|
|
// 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 SetLiteralExpr struct {
|
|
Lbracket Pos // position of left bracket
|
|
Members []Expr // bracketed expression
|
|
Rbracket Pos // position of right bracket
|
|
|
|
ResultDataType ExprDataType
|
|
}
|
|
|
|
func (expr *SetLiteralExpr) IsLiteral() bool {
|
|
return true
|
|
}
|
|
|
|
func (expr *SetLiteralExpr) DataType() ExprDataType {
|
|
return expr.ResultDataType
|
|
}
|
|
|
|
func (expr *SetLiteralExpr) Pos() Pos {
|
|
return expr.Lbracket
|
|
}
|
|
|
|
// Clone returns a deep copy of expr.
|
|
func (expr *SetLiteralExpr) Clone() *SetLiteralExpr {
|
|
if expr == nil {
|
|
return nil
|
|
}
|
|
other := *expr
|
|
other.Members = cloneExprs(expr.Members)
|
|
return &other
|
|
}
|
|
|
|
// String returns the string representation of the expression.
|
|
func (expr *SetLiteralExpr) String() string {
|
|
var buf bytes.Buffer
|
|
|
|
if len(expr.Members) != 0 {
|
|
buf.WriteString("[")
|
|
for i, col := range expr.Members {
|
|
if i != 0 {
|
|
buf.WriteString(", ")
|
|
}
|
|
buf.WriteString(col.String())
|
|
}
|
|
buf.WriteString("]")
|
|
}
|
|
|
|
return buf.String()
|
|
}
|
|
|
|
type TupleLiteralExpr struct {
|
|
Lbrace Pos // position of left brace
|
|
Members []Expr // bracketed expression
|
|
Rbrace Pos // position of right brace
|
|
|
|
ResultDataType ExprDataType
|
|
}
|
|
|
|
func (expr *TupleLiteralExpr) IsLiteral() bool {
|
|
return true
|
|
}
|
|
|
|
func (expr *TupleLiteralExpr) DataType() ExprDataType {
|
|
return expr.ResultDataType
|
|
}
|
|
|
|
func (expr *TupleLiteralExpr) Pos() Pos {
|
|
return expr.Lbrace
|
|
}
|
|
|
|
// Clone returns a deep copy of expr.
|
|
func (expr *TupleLiteralExpr) Clone() *TupleLiteralExpr {
|
|
if expr == nil {
|
|
return nil
|
|
}
|
|
other := *expr
|
|
other.Members = cloneExprs(expr.Members)
|
|
return &other
|
|
}
|
|
|
|
// String returns the string representation of the expression.
|
|
func (expr *TupleLiteralExpr) String() string {
|
|
var buf bytes.Buffer
|
|
|
|
if len(expr.Members) != 0 {
|
|
buf.WriteString("{")
|
|
for i, col := range expr.Members {
|
|
if i != 0 {
|
|
buf.WriteString(", ")
|
|
}
|
|
buf.WriteString(col.String())
|
|
}
|
|
buf.WriteString("}")
|
|
}
|
|
|
|
return buf.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()
|
|
}
|