Skip to content

Commit 047f403

Browse files
kyleconroyclaude
andcommitted
Add AUTOMATIC_TUNING database option parsing support
- Add AutomaticTuningDatabaseOption and sub-option AST types - Parse AUTOMATIC_TUNING = INHERIT|CUSTOM|AUTO - Parse AUTOMATIC_TUNING (CREATE_INDEX = ON, DROP_INDEX = OFF, ...) - Add JSON marshaling for automatic tuning options Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
1 parent e47180f commit 047f403

3 files changed

Lines changed: 153 additions & 0 deletions

File tree

ast/alter_database_set_statement.go

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,58 @@ func (l *LiteralDatabaseOption) node() {}
115115
func (l *LiteralDatabaseOption) databaseOption() {}
116116
func (l *LiteralDatabaseOption) createDatabaseOption() {}
117117

118+
// AutomaticTuningDatabaseOption represents AUTOMATIC_TUNING option
119+
type AutomaticTuningDatabaseOption struct {
120+
OptionKind string // "AutomaticTuning"
121+
AutomaticTuningState string // "Inherit", "Custom", "Auto", "NotSet"
122+
Options []AutomaticTuningOption // Sub-options like CREATE_INDEX, DROP_INDEX, etc.
123+
}
124+
125+
func (a *AutomaticTuningDatabaseOption) node() {}
126+
func (a *AutomaticTuningDatabaseOption) databaseOption() {}
127+
128+
// AutomaticTuningOption is an interface for automatic tuning sub-options
129+
type AutomaticTuningOption interface {
130+
Node
131+
automaticTuningOption()
132+
}
133+
134+
// AutomaticTuningCreateIndexOption represents CREATE_INDEX option
135+
type AutomaticTuningCreateIndexOption struct {
136+
OptionKind string // "Create_Index"
137+
Value string // "On", "Off", "Default"
138+
}
139+
140+
func (a *AutomaticTuningCreateIndexOption) node() {}
141+
func (a *AutomaticTuningCreateIndexOption) automaticTuningOption() {}
142+
143+
// AutomaticTuningDropIndexOption represents DROP_INDEX option
144+
type AutomaticTuningDropIndexOption struct {
145+
OptionKind string // "Drop_Index"
146+
Value string // "On", "Off", "Default"
147+
}
148+
149+
func (a *AutomaticTuningDropIndexOption) node() {}
150+
func (a *AutomaticTuningDropIndexOption) automaticTuningOption() {}
151+
152+
// AutomaticTuningForceLastGoodPlanOption represents FORCE_LAST_GOOD_PLAN option
153+
type AutomaticTuningForceLastGoodPlanOption struct {
154+
OptionKind string // "Force_Last_Good_Plan"
155+
Value string // "On", "Off", "Default"
156+
}
157+
158+
func (a *AutomaticTuningForceLastGoodPlanOption) node() {}
159+
func (a *AutomaticTuningForceLastGoodPlanOption) automaticTuningOption() {}
160+
161+
// AutomaticTuningMaintainIndexOption represents MAINTAIN_INDEX option
162+
type AutomaticTuningMaintainIndexOption struct {
163+
OptionKind string // "Maintain_Index"
164+
Value string // "On", "Off", "Default"
165+
}
166+
167+
func (a *AutomaticTuningMaintainIndexOption) node() {}
168+
func (a *AutomaticTuningMaintainIndexOption) automaticTuningOption() {}
169+
118170
// ElasticPoolSpecification represents SERVICE_OBJECTIVE = ELASTIC_POOL(name = poolname)
119171
type ElasticPoolSpecification struct {
120172
ElasticPoolName *Identifier

parser/marshal.go

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1160,6 +1160,22 @@ func databaseOptionToJSON(opt ast.DatabaseOption) jsonNode {
11601160
"OptionKind": o.OptionKind,
11611161
"OptionState": o.OptionState,
11621162
}
1163+
case *ast.AutomaticTuningDatabaseOption:
1164+
node := jsonNode{
1165+
"$type": "AutomaticTuningDatabaseOption",
1166+
}
1167+
if o.AutomaticTuningState != "" {
1168+
node["AutomaticTuningState"] = o.AutomaticTuningState
1169+
}
1170+
if len(o.Options) > 0 {
1171+
opts := make([]jsonNode, len(o.Options))
1172+
for i, subOpt := range o.Options {
1173+
opts[i] = automaticTuningOptionToJSON(subOpt)
1174+
}
1175+
node["Options"] = opts
1176+
}
1177+
node["OptionKind"] = o.OptionKind
1178+
return node
11631179
case *ast.DelayedDurabilityDatabaseOption:
11641180
return jsonNode{
11651181
"$type": "DelayedDurabilityDatabaseOption",
@@ -1358,6 +1374,37 @@ func databaseOptionToJSON(opt ast.DatabaseOption) jsonNode {
13581374
}
13591375
}
13601376

1377+
func automaticTuningOptionToJSON(opt ast.AutomaticTuningOption) jsonNode {
1378+
switch o := opt.(type) {
1379+
case *ast.AutomaticTuningCreateIndexOption:
1380+
return jsonNode{
1381+
"$type": "AutomaticTuningCreateIndexOption",
1382+
"OptionKind": o.OptionKind,
1383+
"Value": o.Value,
1384+
}
1385+
case *ast.AutomaticTuningDropIndexOption:
1386+
return jsonNode{
1387+
"$type": "AutomaticTuningDropIndexOption",
1388+
"OptionKind": o.OptionKind,
1389+
"Value": o.Value,
1390+
}
1391+
case *ast.AutomaticTuningForceLastGoodPlanOption:
1392+
return jsonNode{
1393+
"$type": "AutomaticTuningForceLastGoodPlanOption",
1394+
"OptionKind": o.OptionKind,
1395+
"Value": o.Value,
1396+
}
1397+
case *ast.AutomaticTuningMaintainIndexOption:
1398+
return jsonNode{
1399+
"$type": "AutomaticTuningMaintainIndexOption",
1400+
"OptionKind": o.OptionKind,
1401+
"Value": o.Value,
1402+
}
1403+
default:
1404+
return jsonNode{"$type": "UnknownAutomaticTuningOption"}
1405+
}
1406+
}
1407+
13611408
func remoteDataArchiveDbSettingToJSON(setting ast.RemoteDataArchiveDbSetting) jsonNode {
13621409
switch s := setting.(type) {
13631410
case *ast.RemoteDataArchiveDbServerSetting:

parser/parse_ddl.go

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2499,6 +2499,60 @@ func (p *Parser) parseAlterDatabaseSetStatement(dbName *ast.Identifier) (*ast.Al
24992499
OptionState: capitalizeFirst(optionValue),
25002500
}
25012501
stmt.Options = append(stmt.Options, opt)
2502+
case "AUTOMATIC_TUNING":
2503+
opt := &ast.AutomaticTuningDatabaseOption{
2504+
OptionKind: "AutomaticTuning",
2505+
AutomaticTuningState: "NotSet",
2506+
}
2507+
// Check for = INHERIT/CUSTOM/AUTO or (sub-options)
2508+
if p.curTok.Type == TokenEquals {
2509+
p.nextToken() // consume =
2510+
stateVal := strings.ToUpper(p.curTok.Literal)
2511+
opt.AutomaticTuningState = capitalizeFirst(stateVal)
2512+
p.nextToken()
2513+
}
2514+
// Parse optional sub-options in parentheses
2515+
if p.curTok.Type == TokenLParen {
2516+
p.nextToken() // consume (
2517+
for p.curTok.Type != TokenRParen && p.curTok.Type != TokenEOF {
2518+
subOptName := strings.ToUpper(p.curTok.Literal)
2519+
p.nextToken() // consume option name
2520+
if p.curTok.Type == TokenEquals {
2521+
p.nextToken() // consume =
2522+
}
2523+
subOptValue := capitalizeFirst(strings.ToUpper(p.curTok.Literal))
2524+
p.nextToken() // consume value
2525+
switch subOptName {
2526+
case "CREATE_INDEX":
2527+
opt.Options = append(opt.Options, &ast.AutomaticTuningCreateIndexOption{
2528+
OptionKind: "Create_Index",
2529+
Value: subOptValue,
2530+
})
2531+
case "DROP_INDEX":
2532+
opt.Options = append(opt.Options, &ast.AutomaticTuningDropIndexOption{
2533+
OptionKind: "Drop_Index",
2534+
Value: subOptValue,
2535+
})
2536+
case "FORCE_LAST_GOOD_PLAN":
2537+
opt.Options = append(opt.Options, &ast.AutomaticTuningForceLastGoodPlanOption{
2538+
OptionKind: "Force_Last_Good_Plan",
2539+
Value: subOptValue,
2540+
})
2541+
case "MAINTAIN_INDEX":
2542+
opt.Options = append(opt.Options, &ast.AutomaticTuningMaintainIndexOption{
2543+
OptionKind: "Maintain_Index",
2544+
Value: subOptValue,
2545+
})
2546+
}
2547+
if p.curTok.Type == TokenComma {
2548+
p.nextToken()
2549+
}
2550+
}
2551+
if p.curTok.Type == TokenRParen {
2552+
p.nextToken() // consume )
2553+
}
2554+
}
2555+
stmt.Options = append(stmt.Options, opt)
25022556
case "DELAYED_DURABILITY":
25032557
// This option uses = with DISABLED/ALLOWED/FORCED values
25042558
if p.curTok.Type != TokenEquals {

0 commit comments

Comments
 (0)