Skip to content

Commit 873a35a

Browse files
kyleconroyclaude
andcommitted
Add ALTER INDEX 140 features support
- Add IGNORE_DUP_KEY with SUPPRESS_MESSAGES option parsing in SET clause - Add RESUMABLE option for REBUILD operations - Add MAX_DURATION as top-level index option for resumable operations - Add WAIT_AT_LOW_PRIORITY as standalone index option - Add indexOption() method to WaitAtLowPriorityOption for ALTER INDEX use - Add WaitAtLowPriorityOption case in indexOptionToJSON - Add boolPtr helper function Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
1 parent bad1829 commit 873a35a

4 files changed

Lines changed: 111 additions & 5 deletions

File tree

ast/drop_statements.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,7 @@ type WaitAtLowPriorityOption struct {
123123

124124
func (o *WaitAtLowPriorityOption) node() {}
125125
func (o *WaitAtLowPriorityOption) dropIndexOption() {}
126+
func (o *WaitAtLowPriorityOption) indexOption() {}
126127

127128
// LowPriorityLockWaitOption is the interface for options within WAIT_AT_LOW_PRIORITY
128129
type LowPriorityLockWaitOption interface {

parser/marshal.go

Lines changed: 108 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,11 @@ import (
1212
// jsonNode represents a generic JSON node from the AST JSON format.
1313
type jsonNode map[string]any
1414

15+
// boolPtr returns a pointer to a bool value.
16+
func boolPtr(b bool) *bool {
17+
return &b
18+
}
19+
1520
// MarshalScript marshals a Script to JSON in the expected format.
1621
func MarshalScript(s *ast.Script) ([]byte, error) {
1722
node := scriptToJSON(s)
@@ -12038,6 +12043,26 @@ func (p *Parser) parseAlterIndexStatement() (*ast.AlterIndexStatement, error) {
1203812043
OptionKind: "IgnoreDupKey",
1203912044
OptionState: p.capitalizeFirst(strings.ToLower(valueUpper)),
1204012045
}
12046+
// Check for (SUPPRESS_MESSAGES = ON/OFF)
12047+
if p.curTok.Type == TokenLParen {
12048+
p.nextToken() // consume (
12049+
if strings.ToUpper(p.curTok.Literal) == "SUPPRESS_MESSAGES" {
12050+
p.nextToken() // consume SUPPRESS_MESSAGES
12051+
if p.curTok.Type == TokenEquals {
12052+
p.nextToken() // consume =
12053+
}
12054+
suppressVal := strings.ToUpper(p.curTok.Literal)
12055+
if suppressVal == "ON" {
12056+
opt.SuppressMessagesOption = boolPtr(true)
12057+
} else if suppressVal == "OFF" {
12058+
opt.SuppressMessagesOption = boolPtr(false)
12059+
}
12060+
p.nextToken()
12061+
}
12062+
if p.curTok.Type == TokenRParen {
12063+
p.nextToken() // consume )
12064+
}
12065+
}
1204112066
stmt.IndexOptions = append(stmt.IndexOptions, opt)
1204212067
} else {
1204312068
opt := &ast.IndexStateOption{
@@ -12109,13 +12134,80 @@ func (p *Parser) parseAlterIndexStatement() (*ast.AlterIndexStatement, error) {
1210912134
optionName := strings.ToUpper(p.curTok.Literal)
1211012135
p.nextToken()
1211112136

12112-
if p.curTok.Type == TokenEquals {
12137+
// Handle WAIT_AT_LOW_PRIORITY (...) - no equals sign
12138+
if optionName == "WAIT_AT_LOW_PRIORITY" && p.curTok.Type == TokenLParen {
12139+
p.nextToken() // consume (
12140+
waitOpt := &ast.WaitAtLowPriorityOption{
12141+
OptionKind: "WaitAtLowPriority",
12142+
}
12143+
for p.curTok.Type != TokenRParen && p.curTok.Type != TokenEOF {
12144+
subOptName := strings.ToUpper(p.curTok.Literal)
12145+
if subOptName == "MAX_DURATION" {
12146+
p.nextToken() // consume MAX_DURATION
12147+
if p.curTok.Type == TokenEquals {
12148+
p.nextToken() // consume =
12149+
}
12150+
durVal, _ := p.parsePrimaryExpression()
12151+
unit := ""
12152+
if strings.ToUpper(p.curTok.Literal) == "MINUTES" {
12153+
unit = "Minutes"
12154+
p.nextToken()
12155+
}
12156+
waitOpt.Options = append(waitOpt.Options, &ast.LowPriorityLockWaitMaxDurationOption{
12157+
MaxDuration: durVal,
12158+
Unit: unit,
12159+
OptionKind: "MaxDuration",
12160+
})
12161+
} else if subOptName == "ABORT_AFTER_WAIT" {
12162+
p.nextToken() // consume ABORT_AFTER_WAIT
12163+
if p.curTok.Type == TokenEquals {
12164+
p.nextToken() // consume =
12165+
}
12166+
abortType := "None"
12167+
switch strings.ToUpper(p.curTok.Literal) {
12168+
case "NONE":
12169+
abortType = "None"
12170+
case "SELF":
12171+
abortType = "Self"
12172+
case "BLOCKERS":
12173+
abortType = "Blockers"
12174+
}
12175+
p.nextToken()
12176+
waitOpt.Options = append(waitOpt.Options, &ast.LowPriorityLockWaitAbortAfterWaitOption{
12177+
AbortAfterWait: abortType,
12178+
OptionKind: "AbortAfterWait",
12179+
})
12180+
} else {
12181+
break
12182+
}
12183+
if p.curTok.Type == TokenComma {
12184+
p.nextToken()
12185+
}
12186+
}
12187+
if p.curTok.Type == TokenRParen {
12188+
p.nextToken() // consume )
12189+
}
12190+
stmt.IndexOptions = append(stmt.IndexOptions, waitOpt)
12191+
} else if p.curTok.Type == TokenEquals {
1211312192
p.nextToken()
1211412193
valueStr := strings.ToUpper(p.curTok.Literal)
1211512194
p.nextToken()
1211612195

12117-
// Determine if it's a state option (ON/OFF) or expression option
12118-
if valueStr == "ON" || valueStr == "OFF" {
12196+
// Handle MAX_DURATION = value [MINUTES] as top-level option
12197+
if optionName == "MAX_DURATION" {
12198+
unit := ""
12199+
if strings.ToUpper(p.curTok.Literal) == "MINUTES" {
12200+
unit = "Minutes"
12201+
p.nextToken()
12202+
}
12203+
opt := &ast.MaxDurationOption{
12204+
MaxDuration: &ast.IntegerLiteral{LiteralType: "Integer", Value: valueStr},
12205+
Unit: unit,
12206+
OptionKind: "MaxDuration",
12207+
}
12208+
stmt.IndexOptions = append(stmt.IndexOptions, opt)
12209+
} else if valueStr == "ON" || valueStr == "OFF" {
12210+
// Determine if it's a state option (ON/OFF) or expression option
1211912211
if optionName == "IGNORE_DUP_KEY" {
1212012212
opt := &ast.IgnoreDupKeyIndexOption{
1212112213
OptionKind: "IgnoreDupKey",
@@ -14646,6 +14738,19 @@ func indexOptionToJSON(opt ast.IndexOption) jsonNode {
1464614738
node["PartitionRanges"] = ranges
1464714739
}
1464814740
return node
14741+
case *ast.WaitAtLowPriorityOption:
14742+
node := jsonNode{
14743+
"$type": "WaitAtLowPriorityOption",
14744+
"OptionKind": o.OptionKind,
14745+
}
14746+
if len(o.Options) > 0 {
14747+
options := make([]jsonNode, len(o.Options))
14748+
for i, opt := range o.Options {
14749+
options[i] = lowPriorityLockWaitOptionToJSON(opt)
14750+
}
14751+
node["Options"] = options
14752+
}
14753+
return node
1464914754
default:
1465014755
return jsonNode{"$type": "UnknownIndexOption"}
1465114756
}
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
{"todo": true}
1+
{}
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
{"todo": true}
1+
{}

0 commit comments

Comments
 (0)