Skip to content

Commit c0f133b

Browse files
committed
Add REMOTE_DATA_ARCHIVE table option parsing for CREATE/ALTER TABLE
Support for: - REMOTE_DATA_ARCHIVE = ON/OFF/OFF_WITHOUT_DATA_RECOVERY - MIGRATION_STATE = PAUSED/OUTBOUND/INBOUND - FILTER_PREDICATE = NULL or function call
1 parent 584fc18 commit c0f133b

5 files changed

Lines changed: 164 additions & 2 deletions

File tree

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
package ast
2+
3+
// RemoteDataArchiveTableOption represents REMOTE_DATA_ARCHIVE option for CREATE TABLE
4+
type RemoteDataArchiveTableOption struct {
5+
RdaTableOption string // "Enable", "Disable", "DisableWithoutDataRecovery"
6+
MigrationState string // "Paused", "Outbound", "Inbound"
7+
FilterPredicate ScalarExpression // Optional filter predicate function call
8+
OptionKind string // "RemoteDataArchive"
9+
}
10+
11+
func (r *RemoteDataArchiveTableOption) node() {}
12+
func (r *RemoteDataArchiveTableOption) tableOption() {}
13+
14+
// RemoteDataArchiveAlterTableOption represents REMOTE_DATA_ARCHIVE option for ALTER TABLE SET
15+
type RemoteDataArchiveAlterTableOption struct {
16+
RdaTableOption string // "Enable", "Disable", "DisableWithoutDataRecovery"
17+
MigrationState string // "Paused", "Outbound", "Inbound"
18+
IsMigrationStateSpecified bool
19+
FilterPredicate ScalarExpression // Optional filter predicate function call
20+
IsFilterPredicateSpecified bool
21+
OptionKind string // "RemoteDataArchive"
22+
}
23+
24+
func (r *RemoteDataArchiveAlterTableOption) node() {}
25+
func (r *RemoteDataArchiveAlterTableOption) tableOption() {}

parser/marshal.go

Lines changed: 131 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4263,6 +4263,12 @@ func (p *Parser) parseCreateTableStatement() (*ast.CreateTableStatement, error)
42634263
OptionKind: "Durability",
42644264
DurabilityTableOptionKind: durabilityKind,
42654265
})
4266+
} else if optionName == "REMOTE_DATA_ARCHIVE" {
4267+
opt, err := p.parseRemoteDataArchiveTableOption(false)
4268+
if err != nil {
4269+
return nil, err
4270+
}
4271+
stmt.Options = append(stmt.Options, opt)
42664272
} else {
42674273
// Skip unknown option value
42684274
if p.curTok.Type == TokenEquals {
@@ -4511,6 +4517,12 @@ func (p *Parser) parseCreateTableOptions(stmt *ast.CreateTableStatement) (*ast.C
45114517
OptionKind: "FileTableFullPathUniqueConstraintName",
45124518
Value: constraintName,
45134519
})
4520+
} else if optionName == "REMOTE_DATA_ARCHIVE" {
4521+
opt, err := p.parseRemoteDataArchiveTableOption(false)
4522+
if err != nil {
4523+
return nil, err
4524+
}
4525+
stmt.Options = append(stmt.Options, opt)
45144526
} else {
45154527
// Skip unknown option value
45164528
if p.curTok.Type == TokenEquals {
@@ -4540,6 +4552,101 @@ func (p *Parser) parseCreateTableOptions(stmt *ast.CreateTableStatement) (*ast.C
45404552
return stmt, nil
45414553
}
45424554

4555+
// parseRemoteDataArchiveTableOption parses REMOTE_DATA_ARCHIVE = ON/OFF (options...) for tables
4556+
// isAlterTable indicates if this is for ALTER TABLE SET (which uses RemoteDataArchiveAlterTableOption)
4557+
func (p *Parser) parseRemoteDataArchiveTableOption(isAlterTable bool) (ast.TableOption, error) {
4558+
// curTok should be = or (
4559+
if p.curTok.Type == TokenEquals {
4560+
p.nextToken() // consume =
4561+
}
4562+
4563+
// Parse ON, OFF, or OFF_WITHOUT_DATA_RECOVERY
4564+
rdaOption := "Enable"
4565+
stateUpper := strings.ToUpper(p.curTok.Literal)
4566+
if stateUpper == "ON" {
4567+
rdaOption = "Enable"
4568+
p.nextToken()
4569+
} else if stateUpper == "OFF" {
4570+
rdaOption = "Disable"
4571+
p.nextToken()
4572+
} else if stateUpper == "OFF_WITHOUT_DATA_RECOVERY" {
4573+
rdaOption = "OffWithoutDataRecovery"
4574+
p.nextToken()
4575+
}
4576+
4577+
var migrationState string
4578+
var filterPredicate ast.ScalarExpression
4579+
isMigrationStateSpecified := false
4580+
isFilterPredicateSpecified := false
4581+
4582+
// Parse options in parentheses
4583+
if p.curTok.Type == TokenLParen {
4584+
p.nextToken() // consume (
4585+
4586+
for p.curTok.Type != TokenRParen && p.curTok.Type != TokenEOF {
4587+
optName := strings.ToUpper(p.curTok.Literal)
4588+
p.nextToken() // consume option name
4589+
4590+
if p.curTok.Type == TokenEquals {
4591+
p.nextToken() // consume =
4592+
}
4593+
4594+
switch optName {
4595+
case "MIGRATION_STATE":
4596+
isMigrationStateSpecified = true
4597+
msUpper := strings.ToUpper(p.curTok.Literal)
4598+
if msUpper == "PAUSED" {
4599+
migrationState = "Paused"
4600+
} else if msUpper == "OUTBOUND" {
4601+
migrationState = "Outbound"
4602+
} else if msUpper == "INBOUND" {
4603+
migrationState = "Inbound"
4604+
}
4605+
p.nextToken()
4606+
case "FILTER_PREDICATE":
4607+
isFilterPredicateSpecified = true
4608+
if strings.ToUpper(p.curTok.Literal) == "NULL" {
4609+
// When FILTER_PREDICATE = NULL, filterPredicate stays nil
4610+
p.nextToken()
4611+
} else {
4612+
// Parse function call like dbo.f1(c1)
4613+
expr, err := p.parseScalarExpression()
4614+
if err != nil {
4615+
return nil, err
4616+
}
4617+
filterPredicate = expr
4618+
}
4619+
}
4620+
4621+
if p.curTok.Type == TokenComma {
4622+
p.nextToken()
4623+
}
4624+
}
4625+
4626+
if p.curTok.Type == TokenRParen {
4627+
p.nextToken() // consume )
4628+
}
4629+
}
4630+
4631+
if isAlterTable {
4632+
return &ast.RemoteDataArchiveAlterTableOption{
4633+
RdaTableOption: rdaOption,
4634+
MigrationState: migrationState,
4635+
IsMigrationStateSpecified: isMigrationStateSpecified,
4636+
FilterPredicate: filterPredicate,
4637+
IsFilterPredicateSpecified: isFilterPredicateSpecified,
4638+
OptionKind: "RemoteDataArchive",
4639+
}, nil
4640+
}
4641+
4642+
return &ast.RemoteDataArchiveTableOption{
4643+
RdaTableOption: rdaOption,
4644+
MigrationState: migrationState,
4645+
FilterPredicate: filterPredicate,
4646+
OptionKind: "RemoteDataArchive",
4647+
}, nil
4648+
}
4649+
45434650
// parseMergeStatement parses a MERGE statement
45444651
func (p *Parser) parseMergeStatement() (*ast.MergeStatement, error) {
45454652
// Consume MERGE
@@ -6926,6 +7033,30 @@ func tableOptionToJSON(opt ast.TableOption) jsonNode {
69267033
node["Value"] = identifierOrValueExpressionToJSON(o.Value)
69277034
}
69287035
return node
7036+
case *ast.RemoteDataArchiveTableOption:
7037+
node := jsonNode{
7038+
"$type": "RemoteDataArchiveTableOption",
7039+
"RdaTableOption": o.RdaTableOption,
7040+
"MigrationState": o.MigrationState,
7041+
"OptionKind": o.OptionKind,
7042+
}
7043+
if o.FilterPredicate != nil {
7044+
node["FilterPredicate"] = scalarExpressionToJSON(o.FilterPredicate)
7045+
}
7046+
return node
7047+
case *ast.RemoteDataArchiveAlterTableOption:
7048+
node := jsonNode{
7049+
"$type": "RemoteDataArchiveAlterTableOption",
7050+
"RdaTableOption": o.RdaTableOption,
7051+
"MigrationState": o.MigrationState,
7052+
"IsMigrationStateSpecified": o.IsMigrationStateSpecified,
7053+
"IsFilterPredicateSpecified": o.IsFilterPredicateSpecified,
7054+
"OptionKind": o.OptionKind,
7055+
}
7056+
if o.FilterPredicate != nil {
7057+
node["FilterPredicate"] = scalarExpressionToJSON(o.FilterPredicate)
7058+
}
7059+
return node
69297060
default:
69307061
return jsonNode{"$type": "UnknownTableOption"}
69317062
}

parser/parse_ddl.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4842,6 +4842,12 @@ func (p *Parser) parseAlterTableSetStatement(tableName *ast.SchemaObjectName) (*
48424842
p.nextToken()
48434843
}
48444844
stmt.Options = append(stmt.Options, opt)
4845+
} else if optionName == "REMOTE_DATA_ARCHIVE" {
4846+
rdaOpt, err := p.parseRemoteDataArchiveTableOption(true)
4847+
if err != nil {
4848+
return nil, err
4849+
}
4850+
stmt.Options = append(stmt.Options, rdaOpt)
48454851
}
48464852

48474853
if p.curTok.Type == TokenComma {
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)