Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion pkg/models/token_type.go
Original file line number Diff line number Diff line change
Expand Up @@ -277,6 +277,7 @@ const (
TokenTypeRefresh TokenType = 375
TokenTypeTies TokenType = 376 // TIES keyword for WITH TIES in FETCH clause
TokenTypePercent TokenType = 377 // PERCENT keyword for FETCH ... PERCENT ROWS
TokenTypeTruncate TokenType = 378 // TRUNCATE keyword for TRUNCATE TABLE statement

// Grouping Set Keywords (390-399)
TokenTypeGroupingSets TokenType = 390
Expand Down Expand Up @@ -545,6 +546,7 @@ var tokenStringMap = map[TokenType]string{
TokenTypeRefresh: "REFRESH",
TokenTypeTies: "TIES",
TokenTypePercent: "PERCENT",
TokenTypeTruncate: "TRUNCATE",

// Grouping Set Keywords
TokenTypeGroupingSets: "GROUPING_SETS",
Expand Down Expand Up @@ -666,7 +668,7 @@ func (t TokenType) IsDMLKeyword() bool {
// IsDDLKeyword returns true if the token type is a DDL keyword
func (t TokenType) IsDDLKeyword() bool {
switch t {
case TokenTypeCreate, TokenTypeAlter, TokenTypeDrop, TokenTypeTable,
case TokenTypeCreate, TokenTypeAlter, TokenTypeDrop, TokenTypeTruncate, TokenTypeTable,
TokenTypeIndex, TokenTypeView, TokenTypeColumn, TokenTypeDatabase,
TokenTypeSchema, TokenTypeTrigger:
return true
Expand Down
13 changes: 13 additions & 0 deletions pkg/sql/ast/ast.go
Original file line number Diff line number Diff line change
Expand Up @@ -1074,6 +1074,19 @@ func (d *DropStatement) statementNode() {}
func (d DropStatement) TokenLiteral() string { return "DROP " + d.ObjectType }
func (d DropStatement) Children() []Node { return nil }

// TruncateStatement represents a TRUNCATE TABLE statement
// Syntax: TRUNCATE [TABLE] table_name [, table_name ...] [RESTART IDENTITY | CONTINUE IDENTITY] [CASCADE | RESTRICT]
type TruncateStatement struct {
Tables []string // Table names to truncate
RestartIdentity bool // RESTART IDENTITY - reset sequences
ContinueIdentity bool // CONTINUE IDENTITY - keep sequences (default)
CascadeType string // CASCADE, RESTRICT, or empty
}

func (t *TruncateStatement) statementNode() {}
func (t TruncateStatement) TokenLiteral() string { return "TRUNCATE TABLE" }
func (t TruncateStatement) Children() []Node { return nil }

// PartitionDefinition represents a partition definition in CREATE TABLE
// Syntax: PARTITION name VALUES { LESS THAN (expr) | IN (list) | FROM (expr) TO (expr) }
type PartitionDefinition struct {
Expand Down
5 changes: 5 additions & 0 deletions pkg/sql/keywords/keywords.go
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,11 @@ var ADDITIONAL_KEYWORDS = []Keyword{
{Word: "OPTION", Type: models.TokenTypeKeyword, Reserved: false, ReservedForTableAlias: false},
{Word: "CASCADED", Type: models.TokenTypeKeyword, Reserved: false, ReservedForTableAlias: false},
{Word: "LOCAL", Type: models.TokenTypeKeyword, Reserved: false, ReservedForTableAlias: false},
// TRUNCATE TABLE statement (SQL:2008)
{Word: "TRUNCATE", Type: models.TokenTypeTruncate, Reserved: true, ReservedForTableAlias: true},
{Word: "RESTART", Type: models.TokenTypeKeyword, Reserved: false, ReservedForTableAlias: false},
{Word: "CONTINUE", Type: models.TokenTypeKeyword, Reserved: false, ReservedForTableAlias: false},
{Word: "IDENTITY", Type: models.TokenTypeKeyword, Reserved: false, ReservedForTableAlias: false},
}

// addKeywordsWithCategory is a helper method to add multiple keywords
Expand Down
54 changes: 54 additions & 0 deletions pkg/sql/parser/ddl.go
Original file line number Diff line number Diff line change
Expand Up @@ -804,3 +804,57 @@ func (p *Parser) parseRefreshStatement() (*ast.RefreshMaterializedViewStatement,

return stmt, nil
}

// parseTruncateStatement parses TRUNCATE TABLE statement
// Syntax: TRUNCATE [TABLE] table_name [, table_name ...] [RESTART IDENTITY | CONTINUE IDENTITY] [CASCADE | RESTRICT]
func (p *Parser) parseTruncateStatement() (*ast.TruncateStatement, error) {
stmt := &ast.TruncateStatement{}

// Optional TABLE keyword
if p.isType(models.TokenTypeTable) {
p.advance() // Consume TABLE
}

// Parse table names (can be comma-separated)
for {
if !p.isType(models.TokenTypeIdentifier) {
return nil, p.expectedError("table name")
}
stmt.Tables = append(stmt.Tables, p.currentToken.Literal)
p.advance()

if p.isType(models.TokenTypeComma) {
p.advance() // Consume comma
continue
}
break
}

// Parse optional RESTART IDENTITY / CONTINUE IDENTITY
if p.isTokenMatch("RESTART") {
p.advance() // Consume RESTART
if !p.isTokenMatch("IDENTITY") {
return nil, p.expectedError("IDENTITY after RESTART")
}
p.advance() // Consume IDENTITY
stmt.RestartIdentity = true
} else if p.isTokenMatch("CONTINUE") {
p.advance() // Consume CONTINUE
if !p.isTokenMatch("IDENTITY") {
return nil, p.expectedError("IDENTITY after CONTINUE")
}
p.advance() // Consume IDENTITY
stmt.ContinueIdentity = true
}

// Parse optional CASCADE/RESTRICT
if p.isType(models.TokenTypeCascade) {
stmt.CascadeType = "CASCADE"
p.advance()
} else if p.isType(models.TokenTypeRestrict) {
stmt.CascadeType = "RESTRICT"
p.advance()
}

return stmt, nil
}
10 changes: 8 additions & 2 deletions pkg/sql/parser/parser.go
Original file line number Diff line number Diff line change
Expand Up @@ -222,7 +222,7 @@ func (p *Parser) Release() {
}

// parseStatement parses a single SQL statement
// Uses fast int-based ModelType comparisons with fallback for hot path optimization
// Uses O(1) switch dispatch on ModelType (compiles to jump table) for optimal performance
func (p *Parser) parseStatement() (ast.Statement, error) {
// Check context if available
if p.ctx != nil {
Expand Down Expand Up @@ -264,6 +264,9 @@ func (p *Parser) parseStatement() (ast.Statement, error) {
case models.TokenTypeRefresh:
p.advance()
return p.parseRefreshStatement()
case models.TokenTypeTruncate:
p.advance()
return p.parseTruncateStatement()
}
// ModelType set but not a statement keyword - fall through to fallback
}
Expand All @@ -273,7 +276,6 @@ func (p *Parser) parseStatement() (ast.Statement, error) {
if p.isType(models.TokenTypeWith) {
return p.parseWithStatement()
}
// Use matchType() for check-and-advance pattern
if p.matchType(models.TokenTypeSelect) {
return p.parseSelectWithSetOperations()
}
Expand Down Expand Up @@ -301,6 +303,9 @@ func (p *Parser) parseStatement() (ast.Statement, error) {
if p.matchType(models.TokenTypeRefresh) {
return p.parseRefreshStatement()
}
if p.matchType(models.TokenTypeTruncate) {
return p.parseTruncateStatement()
}
return nil, p.expectedError("statement")
}

Expand Down Expand Up @@ -387,6 +392,7 @@ var modelTypeToString = map[models.TokenType]token.Type{
models.TokenTypeCreate: "CREATE",
models.TokenTypeAlter: token.ALTER,
models.TokenTypeDrop: token.DROP,
models.TokenTypeTruncate: "TRUNCATE",
models.TokenTypeTable: "TABLE",
models.TokenTypeIndex: "INDEX",
models.TokenTypeView: "VIEW",
Expand Down
1 change: 1 addition & 0 deletions pkg/sql/parser/token_converter.go
Original file line number Diff line number Diff line change
Expand Up @@ -524,6 +524,7 @@ func buildTypeMapping() map[models.TokenType]token.Type {
models.TokenTypeCreate: "CREATE",
models.TokenTypeAlter: "ALTER",
models.TokenTypeDrop: "DROP",
models.TokenTypeTruncate: "TRUNCATE",
models.TokenTypeTable: "TABLE",
models.TokenTypeIndex: "INDEX",
models.TokenTypeView: "VIEW",
Expand Down
Loading
Loading