Skip to content

Commit 21d6e2d

Browse files
committed
Add ONLINE WAIT_AT_LOW_PRIORITY and XML_COMPRESSION support for CREATE INDEX
- Add OnlineIndexLowPriorityLockWaitOption AST type with LowPriorityLockWaitOption field - Parse ONLINE = ON (WAIT_AT_LOW_PRIORITY (MAX_DURATION = N MINUTES, ABORT_AFTER_WAIT = SELF)) - Add XmlCompressionOption indexOption() method for index options - Parse XML_COMPRESSION = ON/OFF [ON PARTITIONS(range)] in CREATE INDEX - Add JSON marshaling for OnlineIndexOption with LowPriorityLockWaitOption - Add JSON marshaling for XmlCompressionOption in index context Enables Baselines160_CreateIndexStatementTests160 and CreateIndexStatementTests160.
1 parent 99e4b3a commit 21d6e2d

7 files changed

Lines changed: 227 additions & 10 deletions

File tree

ast/drop_statements.go

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -81,14 +81,22 @@ type DropIndexOption interface {
8181

8282
// OnlineIndexOption represents the ONLINE option
8383
type OnlineIndexOption struct {
84-
OptionState string // On, Off
85-
OptionKind string // Online
84+
LowPriorityLockWaitOption *OnlineIndexLowPriorityLockWaitOption // For ONLINE = ON (WAIT_AT_LOW_PRIORITY (...))
85+
OptionState string // On, Off
86+
OptionKind string // Online
8687
}
8788

8889
func (o *OnlineIndexOption) node() {}
8990
func (o *OnlineIndexOption) dropIndexOption() {}
9091
func (o *OnlineIndexOption) indexOption() {}
9192

93+
// OnlineIndexLowPriorityLockWaitOption represents WAIT_AT_LOW_PRIORITY options for ONLINE = ON
94+
type OnlineIndexLowPriorityLockWaitOption struct {
95+
Options []LowPriorityLockWaitOption
96+
}
97+
98+
func (o *OnlineIndexLowPriorityLockWaitOption) node() {}
99+
92100
// MoveToDropIndexOption represents the MOVE TO option
93101
type MoveToDropIndexOption struct {
94102
MoveTo *FileGroupOrPartitionScheme

ast/xml_compression_option.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ type XmlCompressionOption struct {
99

1010
func (x *XmlCompressionOption) node() {}
1111
func (x *XmlCompressionOption) tableOption() {}
12+
func (x *XmlCompressionOption) indexOption() {}
1213

1314
// TableXmlCompressionOption represents a table-level XML compression option
1415
type TableXmlCompressionOption struct {

parser/marshal.go

Lines changed: 38 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -853,6 +853,20 @@ func lowPriorityLockWaitOptionToJSON(o ast.LowPriorityLockWaitOption) jsonNode {
853853
}
854854
}
855855

856+
func onlineIndexLowPriorityLockWaitOptionToJSON(o *ast.OnlineIndexLowPriorityLockWaitOption) jsonNode {
857+
node := jsonNode{
858+
"$type": "OnlineIndexLowPriorityLockWaitOption",
859+
}
860+
if len(o.Options) > 0 {
861+
options := make([]jsonNode, len(o.Options))
862+
for i, opt := range o.Options {
863+
options[i] = lowPriorityLockWaitOptionToJSON(opt)
864+
}
865+
node["Options"] = options
866+
}
867+
return node
868+
}
869+
856870
func fileGroupOrPartitionSchemeToJSON(fg *ast.FileGroupOrPartitionScheme) jsonNode {
857871
node := jsonNode{
858872
"$type": "FileGroupOrPartitionScheme",
@@ -13699,11 +13713,15 @@ func indexOptionToJSON(opt ast.IndexOption) jsonNode {
1369913713
"OptionKind": o.OptionKind,
1370013714
}
1370113715
case *ast.OnlineIndexOption:
13702-
return jsonNode{
13716+
node := jsonNode{
1370313717
"$type": "OnlineIndexOption",
1370413718
"OptionState": o.OptionState,
1370513719
"OptionKind": o.OptionKind,
1370613720
}
13721+
if o.LowPriorityLockWaitOption != nil {
13722+
node["LowPriorityLockWaitOption"] = onlineIndexLowPriorityLockWaitOptionToJSON(o.LowPriorityLockWaitOption)
13723+
}
13724+
return node
1370713725
case *ast.CompressionDelayIndexOption:
1370813726
node := jsonNode{
1370913727
"$type": "CompressionDelayIndexOption",
@@ -13726,6 +13744,20 @@ func indexOptionToJSON(opt ast.IndexOption) jsonNode {
1372613744
node["Unit"] = o.Unit
1372713745
}
1372813746
return node
13747+
case *ast.XmlCompressionOption:
13748+
node := jsonNode{
13749+
"$type": "XmlCompressionOption",
13750+
"IsCompressed": o.IsCompressed,
13751+
"OptionKind": o.OptionKind,
13752+
}
13753+
if len(o.PartitionRanges) > 0 {
13754+
ranges := make([]jsonNode, len(o.PartitionRanges))
13755+
for i, r := range o.PartitionRanges {
13756+
ranges[i] = compressionPartitionRangeToJSON(r)
13757+
}
13758+
node["PartitionRanges"] = ranges
13759+
}
13760+
return node
1372913761
default:
1373013762
return jsonNode{"$type": "UnknownIndexOption"}
1373113763
}
@@ -13939,11 +13971,15 @@ func childObjectNameToJSON(s *ast.SchemaObjectName) jsonNode {
1393913971
func dropIndexOptionToJSON(opt ast.DropIndexOption) jsonNode {
1394013972
switch o := opt.(type) {
1394113973
case *ast.OnlineIndexOption:
13942-
return jsonNode{
13974+
node := jsonNode{
1394313975
"$type": "OnlineIndexOption",
1394413976
"OptionState": o.OptionState,
1394513977
"OptionKind": o.OptionKind,
1394613978
}
13979+
if o.LowPriorityLockWaitOption != nil {
13980+
node["LowPriorityLockWaitOption"] = onlineIndexLowPriorityLockWaitOptionToJSON(o.LowPriorityLockWaitOption)
13981+
}
13982+
return node
1394713983
case *ast.MoveToDropIndexOption:
1394813984
node := jsonNode{
1394913985
"$type": "MoveToDropIndexOption",

parser/parse_ddl.go

Lines changed: 67 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1434,10 +1434,75 @@ func (p *Parser) parseDropIndexOptions() []ast.DropIndexOption {
14341434
optState = "On"
14351435
}
14361436
p.nextToken()
1437-
options = append(options, &ast.OnlineIndexOption{
1437+
onlineOpt := &ast.OnlineIndexOption{
14381438
OptionState: optState,
14391439
OptionKind: "Online",
1440-
})
1440+
}
1441+
// Check for optional (WAIT_AT_LOW_PRIORITY (...))
1442+
if optState == "On" && p.curTok.Type == TokenLParen {
1443+
p.nextToken() // consume (
1444+
if strings.ToUpper(p.curTok.Literal) == "WAIT_AT_LOW_PRIORITY" {
1445+
p.nextToken() // consume WAIT_AT_LOW_PRIORITY
1446+
lowPriorityOpt := &ast.OnlineIndexLowPriorityLockWaitOption{}
1447+
if p.curTok.Type == TokenLParen {
1448+
p.nextToken() // consume (
1449+
for p.curTok.Type != TokenRParen && p.curTok.Type != TokenEOF {
1450+
optName := strings.ToUpper(p.curTok.Literal)
1451+
if optName == "MAX_DURATION" {
1452+
p.nextToken() // consume MAX_DURATION
1453+
if p.curTok.Type == TokenEquals {
1454+
p.nextToken() // consume =
1455+
}
1456+
durVal, _ := p.parsePrimaryExpression()
1457+
unit := "Minutes"
1458+
if strings.ToUpper(p.curTok.Literal) == "MINUTES" {
1459+
p.nextToken()
1460+
} else if strings.ToUpper(p.curTok.Literal) == "SECONDS" {
1461+
unit = "Seconds"
1462+
p.nextToken()
1463+
}
1464+
lowPriorityOpt.Options = append(lowPriorityOpt.Options, &ast.LowPriorityLockWaitMaxDurationOption{
1465+
MaxDuration: durVal,
1466+
Unit: unit,
1467+
OptionKind: "MaxDuration",
1468+
})
1469+
} else if optName == "ABORT_AFTER_WAIT" {
1470+
p.nextToken() // consume ABORT_AFTER_WAIT
1471+
if p.curTok.Type == TokenEquals {
1472+
p.nextToken() // consume =
1473+
}
1474+
abortType := "None"
1475+
switch strings.ToUpper(p.curTok.Literal) {
1476+
case "NONE":
1477+
abortType = "None"
1478+
case "SELF":
1479+
abortType = "Self"
1480+
case "BLOCKERS":
1481+
abortType = "Blockers"
1482+
}
1483+
p.nextToken()
1484+
lowPriorityOpt.Options = append(lowPriorityOpt.Options, &ast.LowPriorityLockWaitAbortAfterWaitOption{
1485+
AbortAfterWait: abortType,
1486+
OptionKind: "AbortAfterWait",
1487+
})
1488+
} else {
1489+
break
1490+
}
1491+
if p.curTok.Type == TokenComma {
1492+
p.nextToken()
1493+
}
1494+
}
1495+
if p.curTok.Type == TokenRParen {
1496+
p.nextToken() // consume )
1497+
}
1498+
}
1499+
onlineOpt.LowPriorityLockWaitOption = lowPriorityOpt
1500+
}
1501+
if p.curTok.Type == TokenRParen {
1502+
p.nextToken() // consume )
1503+
}
1504+
}
1505+
options = append(options, onlineOpt)
14411506
case "MOVE":
14421507
p.nextToken() // consume MOVE
14431508
if strings.ToUpper(p.curTok.Literal) == "TO" {

parser/parse_statements.go

Lines changed: 109 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10747,10 +10747,75 @@ func (p *Parser) parseCreateIndexOptions() []ast.IndexOption {
1074710747
OptionState: p.capitalizeFirst(strings.ToLower(valueStr)),
1074810748
})
1074910749
case "ONLINE":
10750-
options = append(options, &ast.OnlineIndexOption{
10750+
onlineOpt := &ast.OnlineIndexOption{
1075110751
OptionKind: "Online",
1075210752
OptionState: p.capitalizeFirst(strings.ToLower(valueStr)),
10753-
})
10753+
}
10754+
// Check for optional (WAIT_AT_LOW_PRIORITY (...))
10755+
if valueStr == "ON" && p.curTok.Type == TokenLParen {
10756+
p.nextToken() // consume (
10757+
if strings.ToUpper(p.curTok.Literal) == "WAIT_AT_LOW_PRIORITY" {
10758+
p.nextToken() // consume WAIT_AT_LOW_PRIORITY
10759+
lowPriorityOpt := &ast.OnlineIndexLowPriorityLockWaitOption{}
10760+
if p.curTok.Type == TokenLParen {
10761+
p.nextToken() // consume (
10762+
for p.curTok.Type != TokenRParen && p.curTok.Type != TokenEOF {
10763+
optName := strings.ToUpper(p.curTok.Literal)
10764+
if optName == "MAX_DURATION" {
10765+
p.nextToken() // consume MAX_DURATION
10766+
if p.curTok.Type == TokenEquals {
10767+
p.nextToken() // consume =
10768+
}
10769+
durVal, _ := p.parsePrimaryExpression()
10770+
unit := "Minutes"
10771+
if strings.ToUpper(p.curTok.Literal) == "MINUTES" {
10772+
p.nextToken()
10773+
} else if strings.ToUpper(p.curTok.Literal) == "SECONDS" {
10774+
unit = "Seconds"
10775+
p.nextToken()
10776+
}
10777+
lowPriorityOpt.Options = append(lowPriorityOpt.Options, &ast.LowPriorityLockWaitMaxDurationOption{
10778+
MaxDuration: durVal,
10779+
Unit: unit,
10780+
OptionKind: "MaxDuration",
10781+
})
10782+
} else if optName == "ABORT_AFTER_WAIT" {
10783+
p.nextToken() // consume ABORT_AFTER_WAIT
10784+
if p.curTok.Type == TokenEquals {
10785+
p.nextToken() // consume =
10786+
}
10787+
abortType := "None"
10788+
switch strings.ToUpper(p.curTok.Literal) {
10789+
case "NONE":
10790+
abortType = "None"
10791+
case "SELF":
10792+
abortType = "Self"
10793+
case "BLOCKERS":
10794+
abortType = "Blockers"
10795+
}
10796+
p.nextToken()
10797+
lowPriorityOpt.Options = append(lowPriorityOpt.Options, &ast.LowPriorityLockWaitAbortAfterWaitOption{
10798+
AbortAfterWait: abortType,
10799+
OptionKind: "AbortAfterWait",
10800+
})
10801+
} else {
10802+
break
10803+
}
10804+
if p.curTok.Type == TokenComma {
10805+
p.nextToken()
10806+
}
10807+
}
10808+
if p.curTok.Type == TokenRParen {
10809+
p.nextToken() // consume )
10810+
}
10811+
}
10812+
onlineOpt.LowPriorityLockWaitOption = lowPriorityOpt
10813+
}
10814+
if p.curTok.Type == TokenRParen {
10815+
p.nextToken() // consume )
10816+
}
10817+
}
10818+
options = append(options, onlineOpt)
1075410819
case "ALLOW_ROW_LOCKS":
1075510820
options = append(options, &ast.IndexStateOption{
1075610821
OptionKind: "AllowRowLocks",
@@ -10829,6 +10894,48 @@ func (p *Parser) parseCreateIndexOptions() []ast.IndexOption {
1082910894
}
1083010895
}
1083110896
options = append(options, opt)
10897+
case "XML_COMPRESSION":
10898+
// Parse XML_COMPRESSION = ON/OFF [ON PARTITIONS(range)]
10899+
isCompressed := "On"
10900+
if valueStr == "OFF" {
10901+
isCompressed = "Off"
10902+
}
10903+
opt := &ast.XmlCompressionOption{
10904+
IsCompressed: isCompressed,
10905+
OptionKind: "XmlCompression",
10906+
}
10907+
// Check for optional ON PARTITIONS(range)
10908+
if p.curTok.Type == TokenOn {
10909+
p.nextToken() // consume ON
10910+
if strings.ToUpper(p.curTok.Literal) == "PARTITIONS" {
10911+
p.nextToken() // consume PARTITIONS
10912+
if p.curTok.Type == TokenLParen {
10913+
p.nextToken() // consume (
10914+
for p.curTok.Type != TokenRParen && p.curTok.Type != TokenEOF {
10915+
partRange := &ast.CompressionPartitionRange{}
10916+
// Parse From value
10917+
partRange.From = &ast.IntegerLiteral{LiteralType: "Integer", Value: p.curTok.Literal}
10918+
p.nextToken()
10919+
// Check for TO keyword indicating a range
10920+
if strings.ToUpper(p.curTok.Literal) == "TO" {
10921+
p.nextToken() // consume TO
10922+
partRange.To = &ast.IntegerLiteral{LiteralType: "Integer", Value: p.curTok.Literal}
10923+
p.nextToken()
10924+
}
10925+
opt.PartitionRanges = append(opt.PartitionRanges, partRange)
10926+
if p.curTok.Type == TokenComma {
10927+
p.nextToken()
10928+
} else {
10929+
break
10930+
}
10931+
}
10932+
if p.curTok.Type == TokenRParen {
10933+
p.nextToken() // consume )
10934+
}
10935+
}
10936+
}
10937+
}
10938+
options = append(options, opt)
1083210939
default:
1083310940
// Generic handling for other options
1083410941
if valueStr == "ON" || valueStr == "OFF" {
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)